package AFX::Visual;

=head1 NAME

AFX::Visual - Visual Frame

  new()                             - Frame constructor
  on_frame_close()                  - Event: Frame close
  on_left_atf_page_activated()      - Event: ATF Element Activated
  on_left_atf_page_expanding()      - Event: ATF Element Expanding
  on_left_atf_page_menu()           - Event: ATF Element Menu
  on_left_opened_activated()        - Event: Opened Element Activated
  on_left_opened_menu()             - Event: Opened Element Menu
  on_left_stf_page_activated()      - Event: STF Element Activated
  on_left_stf_page_menu()           - Event: STF Element Menu
  on_right_main_page_changed()      - Event: Right Page (Editor) Changed
  on_right_main_page_close()        - Event: Right Page (Editor) Close
  on_right_slave_hint_changed()     - Event: Right Slave Hint Changed
  on_right_slave_page_changed()     - Event: Right Slave Page Changed
  on_right_slave_page_close()       - Event: Right Slave Page Close
  on_right_slave_param_id_changed() - Event: Right Slave Parameter Id Changed
  on_right_slave_refer_changed()    - Event: Right Slave Referrer Changed
  on_right_slave_source_changed()   - Event: Right Slave Source Changed
  set_frame()                       - Set Frame
  set_left_atf_page()               - Populate Templates into Tree
  set_left_opened_tree()            - Set Opened Tree
  set_left_site_page()              - Populate Sites into Tree
  set_left_stf_page()               - Populate Scenarios into Tree
  set_menubar()                     - Set Frame's Menubar
  set_right_main_xml()              - Set Right XML
  set_right_slave_command()         - Set Right Slave Command
  set_right_slave_layout()          - Set Right Slave Layout
  set_right_slave_param()           - Set Right Slave Parameter
  set_right_slave_refer()           - Set Right Slave Referrer
  set_right_slave_source()          - Set Right Slave Source
  show_about()                      - Event: Frame About

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2010 Mikhail Volkov

This file is part of AuditFX.

    AuditFX is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    AuditFX is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with AuditFX.  If not, see <http://www.gnu.org/licenses/>.
=cut

use strict;
use Carp;
use Exporter ();

my @ISA     = qw(Exporter);
my $VERSION = '1.0';

##############################################################################
# Globals
#

use Wx::AUI;
use Wx::STC;
use Wx::Html;
use base qw(Wx::Frame);
use Wx qw(wxDefaultPosition wxDefaultSize wxAUI_NB_DEFAULT_STYLE);
use Algorithm::Diff;
use Net::IP;

use AFX::ATF;

##############################################################################
#
# add_new_site()
#
# Dialog: New Site

sub add_new_site {
    my ($self) = @_;

    use Wx qw(wxID_CANCEL);

## Create Dialog
    my $dialog =
      Wx::TextEntryDialog->new( $self, "Enter new site name", "New Site", "" );

## Check dialog button
    return 0 if $dialog->ShowModal() == wxID_CANCEL;

## Get site_id
    my $site_id = uc( $dialog->GetValue() );

## Open default ASF
    my $asf = new AFX::ASF( $self->{Process}->{ACF}, $site_id );

## Return Error If ASF not opened
    return 0 if !$asf;

## Add Master File
    $asf->add_master($site_id);

## Destroy dialog
    $dialog->Destroy;

## Set Site Tree
    $self->set_left_site_page();

## Return Ok
    return 1;
}

##############################################################################
#
# delete_site()
#
# Dialog: Delete Site
#
# Arguments expected are:
# - self          - Object reference
# - site_id       - Site's Identifier

sub delete_site {
    my ( $self, $site_id ) = @_;

    use Wx qw(wxYES_NO wxNO wxCENTRE);

## Show Dialog
    my $answer =
      Wx::MessageBox( "Are you sure you want to delete '$site_id' site?",
        "Confirm", wxYES_NO | wxCENTRE, $self );

## Return if no choosen
    return 0 if $answer == wxNO;

## Open default ASF
    my $asf = new AFX::ASF( $self->{Process}->{ACF}, $site_id );

## Return Error If ASF not opened
    return 0 if !$asf;

## Delete Master File
    $asf->delete_master($site_id);

## Set Site Tree
    $self->set_left_site_page();

## Return Ok
    return 1;
}

##############################################################################
#
# new()
#
# Frame constructor
#
# Arguments expected are:
# - Process's Object
# - ARF's Object

sub new {
    my ( $class, $process, $arf ) = @_;

    use Wx qw(wxID_EXIT wxID_ABOUT wxDEFAULT_FRAME_STYLE wxTR_HIDE_ROOT
      wxTR_DEFAULT_STYLE wxTE_MULTILINE wxTE_READONLY);

## Set name
    my $name = $process->{ACF}->get_title('name');
    my $title = "$name->{content} Visual" if $name;

## Create Frame
    my $self =
      $class->SUPER::new( undef, -1, $title, wxDefaultPosition, [ 800, 600 ],
        wxDEFAULT_FRAME_STYLE );

## Set title, version and config
    $self->{title}   = $title;
    $self->{version} = $process->{ACF}->get_version();

## Set Proccess Object
    $self->{Process} = $process;

## Set ARF Object
    $self->{ARF} = $arf;

## Initialize images
    Wx::InitAllImageHandlers();

## Create menu bar
    $self->set_menubar();

## Create frame
    $self->set_frame();

## Set Icon
    $self->SetIcon( Wx::GetWxPerlIcon() );

## Show Frame
    $self->Show;
    $self->Centre();

## Return object
    return $self;
}

##############################################################################
#
# on_frame_close()
#
# Event: Frame close
#
# Arguments expected are:
# - Process's Object
# - ARF's Object

sub on_frame_close {
    my ( $self, $event ) = @_;

## Get Right notebook
    my $right_nb = $self->{right_nb};

## Check all pages
    while ( $right_nb->GetPageCount() ) {

## Select opened page
        $right_nb->SetSelection(0);

## Event on page close
        $self->on_right_main_page_close($event);

## Remove page
        $right_nb->DeletePage(0);
    }

## Restore Log
    Wx::Log::SetActiveTarget( $self->{OLDLOG} );

## Processing Event
    $event->Skip();
}

##############################################################################
#
# on_left_atf_page_activated()
#
# Event: ATF Element Activated
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_left_atf_page_activated {
    my ( $self, $event ) = @_;

    use Wx qw(wxAUI_NB_BOTTOM);

## Get Right Notebook
    my $right_nb = $self->{right_nb};

## Get Id from Tree
    my $template_id = $self->{atf_page}->GetPlData( $event->GetItem() );

## Check all pages
    foreach my $page_num ( 0 .. $right_nb->GetPageCount() ) {

## Get page text
        my $page_text = $right_nb->GetPageText($page_num);

## Skip if page not equal template
        next
          if $page_text ne "ATF:$template_id"
              and $page_text ne "*ATF:$template_id";

## Select already opened page
        $right_nb->SetSelection($page_num);

## Return Error
        return 0;
    }

## Add notebook into Right Splitter
    my $main_page =
      Wx::AuiNotebook->new( $right_nb, -1, wxDefaultPosition, wxDefaultSize,
        wxAUI_NB_DEFAULT_STYLE | wxAUI_NB_BOTTOM );

## Open ATF
    $main_page->{atf} = new AFX::ATF( $self->{ARF}, $template_id, 'template' );

## If ATF wasn't opened
    if ( !$main_page->{atf} ) {

## Add item into root
        Wx::LogMessage("Can't open $template_id!");

## Return Error
        return 0;
    }

## Save original ATF
    $main_page->{xml_original} = $main_page->{atf}->get_xml();
    $main_page->{xml_type}     = "ATF";

## Set Page Source
    $self->set_right_slave_source( $main_page, 0 );

## Add page to notebook
    $main_page->AddPage( $main_page->{source}, "Source", 1 );

## Set ATF Notebook Events
    Wx::Event::EVT_AUINOTEBOOK_PAGE_CLOSE( $self, $main_page,
        \&on_right_slave_page_close );

    Wx::Event::EVT_AUINOTEBOOK_PAGE_CHANGED( $self, $main_page,
        \&on_right_slave_page_changed );

## Add page to notebook
    $right_nb->AddPage( $main_page,
        $main_page->{xml_type} . ":" . $main_page->{atf}->get_id(), 1 );

## Set Opened Page
    $self->set_left_opened_tree($main_page);

## Return Ok
    return 1;
}

##############################################################################
#
# on_left_atf_page_expanding()
#
# Event: ATF Element Expanding
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_left_atf_page_expanding {
    my ( $self, $event ) = @_;

## Get Id from Tree
    my $item = $event->GetItem();

## Return Error if atf_page wasn't defined
    return 0 if !$self->{atf_page};

## Delete all childrens
    $self->{atf_page}->DeleteChildren($item);

## Get Id from Tree
    my $template_id = $self->{atf_page}->GetPlData($item);

## Open ATF
    my $atf = new AFX::ATF( $self->{ARF}, $template_id, 'template' );

## If ATF wasn't opened
    if ( !$atf or !$atf->get_list_machine() ) {

## Add item into root
        $self->{atf_page}
          ->AppendItem( $item, 'N/A', 0, 1, Wx::TreeItemData->new('N/A') );

## Return Error
        return 0;
    }

## Set New Item's Text
    $self->{atf_page}->SetItemText( $item,
        "$atf->{id} (" . $atf->get_version() . ", " . $atf->get_type() . ")" );

## Check Machines in template
    foreach my $machine ( @{ $atf->get_list_machine() } ) {

## Check referrer for machine
        foreach my $refer ( @{ $machine->{refer} } ) {

## Skip wrong referrer
            next if !$refer->{template};

## Add item into root
            my $refer_item =
              $self->{atf_page}
              ->AppendItem( $item, "$refer->{template} [$refer->{id}]",
                0, 1, Wx::TreeItemData->new( $refer->{template} ) )
              if $atf;

## Add item into template
            $self->{atf_page}->AppendItem( $refer_item, "...", 0, 1,
                Wx::TreeItemData->new("...") )
              if $refer_item;
        }
    }

## Sort Children
    $self->{atf_page}->SortChildren($item);

## Return Ok
    return 1;
}

##############################################################################
#
# on_left_atf_page_menu()
#
# Event: ATF Element Menu
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_left_atf_page_menu {
    my ( $self, $event ) = @_;

## Return Error if atf_page wasn't defined
    return 0 if !$self->{atf_page};

## Get Id from Tree
    my $template_id = $self->{atf_page}->GetPlData( $event->GetItem() );

## Create Popup menu
    my $atf = Wx::Menu->new();

## Set Atf Events
    Wx::Event::EVT_MENU(
        $self,
        $atf->Append( -1, "&New" ),
        sub { Wx::LogMessage("TODO: New ATF"); }
    );
    Wx::Event::EVT_MENU(
        $self,
        $atf->Append( -1, "&Open" ),
        sub { $self->on_left_atf_page_activated($event) }
    );
    $atf->AppendSeparator();

## Edit
    Wx::Event::EVT_MENU(
        $self,
        $atf->Append( -1, "&Edit Property" ),
        sub {
            $self->on_left_atf_page_activated($event);
            $self->set_right_slave_page_property($template_id);
        }
    );

## Refresh
    $atf->AppendSeparator();
    Wx::Event::EVT_MENU(
        $self,
        $atf->Append( -1, "&Refresh" ),
        sub {
            $self->on_left_atf_page_expanding($event);
            $self->{atf_page}->Expand( $event->GetItem );
        }
    );

## Show Context Menu
    $self->PopupMenu( $atf, wxDefaultPosition );

## Return Ok
    return 1;
}

##############################################################################
#
# on_left_opened_activated()
#
# Event: Left Opened Element Activated
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_left_opened_activated {
    my ( $self, $event ) = @_;

## Return error if main page wasn't defined
    return 0 if !$self->{right_nb} or !$self->{opened};

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Return Error if selected nothing
    return 0 if !$main_page;

## If it is ATF/ASF Page
    if (   ( $main_page->{atf} and $main_page->{atf}->is_updated() )
        or ( $main_page->{asf} and $main_page->{asf}->is_updated() ) )
    {

## Update ATF XML
        $self->set_right_main_xml($main_page);
    }

## Get Item Text from Tree
    my $item_text = $self->{opened}->GetItemText( $event->GetItem() );

## If ATF specified
    if ( $main_page->{atf} ) {

        if ( $item_text eq $main_page->{atf}->get_id() ) {

## Open ATF Proparty for Design
            $self->set_right_slave_page_property($item_text);
        }
        else {

## Open ATF Step for Design
            $self->set_right_slave_page_step($item_text);
        }
    }

## If ASF specified
    if ( $main_page->{asf} ) {

        if ( $item_text eq $main_page->{asf}->get_id() ) {

## Open ASF Master for Design
            $self->set_right_slave_page_master($item_text);
        }
        else {

## Get Item parent
            my $item_parent =
              $self->{opened}->GetItemParent( $event->GetItem() );
            my $item_parent_text = $self->{opened}->GetItemText($item_parent);

## Open ASF Machine for Design
            $self->set_right_slave_page_machine( $item_text,
                $item_parent_text );
        }
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_left_opened_menu()
#
# Event: Opened Element Menu
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_left_opened_menu {
    my ( $self, $event ) = @_;

## Return error if main page wasn't defined
    return 0 if !$self->{right_nb} or !$self->{opened};

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Return Error if main page wasn't defined
    return 0 if !$main_page;

## Get Item Text from Tree
    my $item_text = $self->{opened}->GetItemText( $event->GetItem() );

## Create Opened menu
    my $opened = Wx::Menu->new();

## Set Atf Events
    Wx::Event::EVT_MENU(
        $self,
        $opened->Append( -1, "&New" ),
        sub { Wx::LogMessage("TODO: New Step"); }
    );
    Wx::Event::EVT_MENU(
        $self,
        $opened->Append( -1, "&Open" ),
        sub { $self->on_left_opened_activated($event) }
    );
    $opened->AppendSeparator();

## If it's ASF
    if ( $main_page->{asf} ) {

## Get Item parent
        my $item_parent = $self->{opened}->GetItemParent( $event->GetItem() );
        my $item_parent_text = $self->{opened}->GetItemText($item_parent);

        Wx::Event::EVT_MENU(
            $self,
            $opened->Append( -1, "&Execute RCmd" ),
            sub {
                $self->set_right_slave_page_rcmd( $item_text,
                    $item_parent_text );
            }
        );

        $opened->AppendSeparator();
    }

## Refresh
    Wx::Event::EVT_MENU(
        $self,
        $opened->Append( -1, "&Refresh" ),
        sub {
            $self->set_right_main_xml($main_page);
            $self->set_left_opened_tree($main_page);
        }
    );

## Show Context Menu
    $self->PopupMenu( $opened, wxDefaultPosition );

## Return Ok
    return 1;
}

##############################################################################
#
# on_left_page_close()
#
# Event: Left Page Close
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_left_page_close {
    my ( $self, $event ) = @_;

## Set Left Notebook
    my $left_nb = $self->{left_nb};

## Get selected page
    my $page      = $left_nb->GetPage( $left_nb->GetSelection() );
    my $page_text = $left_nb->GetPageText( $left_nb->GetSelection() );

## Return Error If page wasn't defined
    return 0 if !$page;

## If it is Site Page
    if ( $page_text =~ "^Site" ) {

## Log Message
        Wx::LogMessage("DEBUG: Site reopened");

## Delete old site
        delete( $self->{site_page} );

## Reopen Site
        $self->set_left_site_page();
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_left_site_page_activated()
#
# Event: STF Element Activated
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_left_site_page_activated {
    my ( $self, $event ) = @_;

    use Wx qw(wxAUI_NB_BOTTOM);

## Get Right Notebook
    my $right_nb = $self->{right_nb};

## Get Id from Tree
    my $site_id = $self->{site_page}->GetPlData( $event->GetItem() );

## Check all pages
    foreach my $page_num ( 0 .. $right_nb->GetPageCount() ) {

## Get page text
        my $page_text = $right_nb->GetPageText($page_num);

## Skip if page not equal template
        next
          if $page_text ne "Site:$site_id"
              and $page_text ne "*Site:$site_id";

## Select already opened page
        $right_nb->SetSelection($page_num);

## Return Error
        return 0;
    }

## Add notebook into Right Splitter
    my $main_page =
      Wx::AuiNotebook->new( $right_nb, -1, wxDefaultPosition, wxDefaultSize,
        wxAUI_NB_DEFAULT_STYLE | wxAUI_NB_BOTTOM );

## Open Site
    $main_page->{asf} = new AFX::ASF( $self->{Process}->{ACF}, $site_id );

## If Site wasn't opened
    if ( !$main_page->{asf} ) {

## Log Message
        Wx::LogMessage("Can't open $site_id!");

## Return Error
        return 0;
    }

## Save original ASF
    $main_page->{xml_original} = $main_page->{asf}->get_xml();

## Set Page Source
    $self->set_right_slave_source( $main_page, 0 );

## Add page to notebook
    $main_page->AddPage( $main_page->{source}, "Source", 1 );

## Set STF Notebook Events
    Wx::Event::EVT_AUINOTEBOOK_PAGE_CLOSE( $self, $main_page,
        \&on_right_slave_page_close );
    Wx::Event::EVT_AUINOTEBOOK_PAGE_CHANGED( $self, $main_page,
        \&on_right_slave_page_changed );

## Add page to notebook
    $right_nb->AddPage( $main_page, "Site:" . $main_page->{asf}->get_id(), 1 );

## Set Opened Page
    $self->set_left_opened_tree($main_page);
    $self->set_right_slave_page_master($site_id);
    
## Return Ok
    return 1;
}

##############################################################################
#
# on_left_site_page_menu()
#
# Event: Site Element Menu
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_left_site_page_menu {
    my ( $self, $event ) = @_;

    use Wx qw(wxTE_MULTILINE wxHORIZONTAL wxVERTICAL wxALL wxEXPAND
      wxCENTRE);

## Return Error if atf_page wasn't defined
    return 0 if !$self->{site_page};

## Get Id from Tree
    my $site_id = $self->{site_page}->GetPlData( $event->GetItem() );

## Create Popup menu
    my $site = Wx::Menu->new();

## Set Site Events
    Wx::Event::EVT_MENU(
        $self,
        $site->Append( -1, "&New" ),
        sub { $self->add_new_site(); }
    );
    Wx::Event::EVT_MENU(
        $self,
        $site->Append( -1, "&Open" ),
        sub { $self->on_left_site_page_activated($event) }
    );
    $site->AppendSeparator();
    Wx::Event::EVT_MENU(
        $self,
        $site->Append( -1, "&Edit Master File" ),
        sub {
            $self->on_left_site_page_activated($event);
            $self->set_right_slave_page_master($site_id);
        }
    );
    $site->AppendSeparator();
    Wx::Event::EVT_MENU(
        $self,
        $site->Append( -1, "&Delete" ),
        sub { $self->delete_site($site_id); }
    );

## Show Context Menu
    $self->PopupMenu( $site, wxDefaultPosition );

## Return Ok
    return 1;
}

##############################################################################
#
# on_left_stf_page_activated()
#
# Event: STF Element Activated
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_left_stf_page_activated {
    my ( $self, $event ) = @_;

    use Wx qw(wxAUI_NB_BOTTOM);

## Get Right Notebook
    my $right_nb = $self->{right_nb};

## Get Id from Tree
    my $scenario_id = $self->{stf_page}->GetPlData( $event->GetItem() );

## Check all pages
    foreach my $page_num ( 0 .. $right_nb->GetPageCount() ) {

## Get page text
        my $page_text = $right_nb->GetPageText($page_num);

## Skip if page not equal template
        next
          if $page_text ne "STF:$scenario_id"
              and $page_text ne "*STF:$scenario_id";

## Select already opened page
        $right_nb->SetSelection($page_num);

## Return Error
        return 0;
    }

## Add notebook into Right Splitter
    my $main_page =
      Wx::AuiNotebook->new( $right_nb, -1, wxDefaultPosition, wxDefaultSize,
        wxAUI_NB_DEFAULT_STYLE | wxAUI_NB_BOTTOM );

## Open STF
    $main_page->{atf} = new AFX::ATF( $self->{ARF}, $scenario_id, 'scenario' );

## If STF wasn't opened
    if ( !$main_page->{atf} ) {

## Log Message
        Wx::LogMessage("Can't open $scenario_id!");

## Return Error
        return 0;
    }

## Save original STF
    $main_page->{xml_original} = $main_page->{atf}->get_xml();
    $main_page->{xml_type}     = "STF";

## Set Page Source
    $self->set_right_slave_source( $main_page, 0 );

## Add page to notebook
    $main_page->AddPage( $main_page->{source}, "Source", 1 );

## Set STF Notebook Events
    Wx::Event::EVT_AUINOTEBOOK_PAGE_CLOSE( $self, $main_page,
        \&on_right_slave_page_close );
    Wx::Event::EVT_AUINOTEBOOK_PAGE_CHANGED( $self, $main_page,
        \&on_right_slave_page_changed );

## Add page to notebook
    $right_nb->AddPage( $main_page,
        $main_page->{xml_type} . ":" . $main_page->{atf}->get_id(), 1 );

## Set Opened Page
    $self->set_left_opened_tree($main_page);

## Return Ok
    return 1;
}

##############################################################################
#
# on_left_stf_page_menu()
#
# Event: STF Element Menu
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_left_stf_page_menu {
    my ( $self, $event ) = @_;

## Return Error if atf_page wasn't defined
    return 0 if !$self->{stf_page};

## Get Id from Tree
    my $scenario_id = $self->{stf_page}->GetPlData( $event->GetItem() );

## Create Popup menu
    my $stf = Wx::Menu->new();

## Set Stf Events
    Wx::Event::EVT_MENU(
        $self,
        $stf->Append( -1, "&New" ),
        sub { Wx::LogMessage("TODO: New STF"); }
    );
    Wx::Event::EVT_MENU(
        $self,
        $stf->Append( -1, "&Open" ),
        sub { $self->on_left_stf_page_activated($event) }
    );
    $stf->AppendSeparator();

## Edit
    Wx::Event::EVT_MENU(
        $self,
        $stf->Append( -1, "&Edit Property" ),
        sub {
            $self->on_left_stf_page_activated($event);
            $self->set_right_slave_page_property($scenario_id);
        }
    );

## Show Context Menu
    $self->PopupMenu( $stf, wxDefaultPosition );

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_main_page_changed()
#
# Event: Right Main Page Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_main_page_changed {
    my ( $self, $event ) = @_;

## Return error if main page wasn't defined
    return 0 if !$self->{right_nb};

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Return Error if main page wasn't defined
    return 0 if !$main_page;

## Set Opened Page
    $self->set_left_opened_tree($main_page);

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_main_page_close()
#
# Event: Right Page (Editor) Close
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_main_page_close {
    my ( $self, $event ) = @_;

    use Wx qw(wxYES_NO wxNO wxCENTRE);

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Return Ok If Last page closed
    return 1 if !$main_page;

## Set Opened ATF
    $self->set_left_opened_tree();

## Check all pages
    foreach my $page_num ( 0 .. $main_page->GetPageCount() ) {

## Get selected page in right
        my $slave_page = $main_page->GetPage($page_num);
        my $slave_text = $main_page->GetPageText($page_num);

## Skip Source page
        next if $slave_text =~ "^Source";

## Close Slave page
        $self->on_right_slave_page_close($event);
    }

## Define answer
    my $answer;

## If Page with ATF closed
    if ( $main_page->{atf} and $main_page->{atf}->is_updated() ) {

## Get ATF Id
        my $atf_id   = $main_page->{atf}->get_id();
        my $atf_type = $main_page->{xml_type};

## Show Dialog
        $answer = Wx::MessageBox( "Save $atf_type:$atf_id changes?",
            "Confirm", wxYES_NO | wxCENTRE, $self );
    }

## If Page with ASF closed
    if ( $main_page->{asf} and $main_page->{asf}->is_updated() ) {

## Get ASF Id
        my $asf_id = $main_page->{asf}->get_id();

## Show Dialog
        $answer = Wx::MessageBox(
            "Save Site:$asf_id changes?", "Confirm",
            wxYES_NO | wxCENTRE,          $self
        );
    }

## Return if no saving
    return 0 if $answer == wxNO;

## If ATF closed and save changes
    if ( $main_page->{atf} and $main_page->{atf}->is_updated() ) {

## Log message
        Wx::LogMessage( "Saving changes for " . $main_page->{atf}->get_id() );

## Update ATF XML
        $self->set_right_main_xml($main_page);

## Update ATF
        $main_page->{atf}->update();

## Return Error
        return 1;
    }

## If ASF closed and save changes
    if ( $main_page->{asf} and $main_page->{asf}->is_updated() ) {

## Log message
        Wx::LogMessage( "Saving changes for " . $main_page->{asf}->get_id() );

## Update ASF XML
        $self->set_right_main_xml($main_page);

## Update ASF
        $main_page->{asf}->update();

## Return Error
        return 1;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_command_content_changed()
#
# Event: Right Slave Command Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_command_content_changed {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Get new command
    my $new_command = $event->GetString();

## Get first command
    my $command = $slave_page->{step}->{command}->[0]
      if $slave_page->{step}->{command};

## If content changed
    if ( $command and $command->{content} ne $new_command ) {

## Update command
        $command->{content} = $new_command;

## Set XML Updated
        $main_page->{atf}->{updated}++;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_command_end_changed()
#
# Event: Right Slave Command End Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_command_end_changed {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Get new end
    my $new_end = $event->GetString();

## Get first command
    my $command = $slave_page->{step}->{command}->[0]
      if $slave_page->{step}->{command};

## If end changed
    if ( $command and $command->{end} ne $new_end ) {

## Update end
        $command->{end} = $new_end;

## Set XML Updated
        $main_page->{atf}->{updated}++;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_command_login_changed()
#
# Event: Right Slave Command Login Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_command_login_changed {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Get new login
    my $new_login = $event->GetString();

## Get first command
    my $command = $slave_page->{step}->{command}->[0]
      if $slave_page->{step}->{command};

## If login changed
    if ( $command and $command->{login} ne $new_login ) {

## Update login
        $command->{login} = $new_login;

## Set XML Updated
        $main_page->{atf}->{updated}++;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_command_passwd_changed()
#
# Event: Right Slave Command Password Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_command_passwd_changed {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Get new passwd
    my $new_passwd = $event->GetString();

## Get first command
    my $command = $slave_page->{step}->{command}->[0]
      if $slave_page->{step}->{command};

## If passwd changed
    if ( $command and $command->{passwd} ne $new_passwd ) {

## Update passwd
        $command->{passwd} = $new_passwd;

## Set XML Updated
        $main_page->{atf}->{updated}++;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_command_timeout_changed()
#
# Event: Right Slave Command Timeout Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_command_timeout_changed {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Get new timeout
    my $new_timeout = $event->GetString();

## Get first command
    my $command = $slave_page->{step}->{command}->[0]
      if $slave_page->{step}->{command};

## If timeout changed
    if ( $command and $command->{timeout} ne $new_timeout ) {

## Update timeout
        $command->{timeout} = $new_timeout;

## Set XML Updated
        $main_page->{atf}->{updated}++;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_hint_changed()
#
# Event: Right Slave Hint Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_hint_changed {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Get new hint
    my $new_hint = $slave_page->{hint_ctrl}->GetValue();

## Set Command Hint
    my $hint = $self->{ARF}->get_step_hint( $slave_page->{step} );

## If hint exists
    if ( $hint and $hint->{content} ne $new_hint ) {

## Update hint
        $hint->{content} = $new_hint;

## Set XML Updated
        $main_page->{atf}->{updated}++;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_terminal_idle_changed()
#
# Event: Right Slave Terminal Idle Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_terminal_idle_changed {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Get Node
    my $node = $main_page->{asf}->get_machine_node( $slave_page->{machine},
        $slave_page->{node_id_ctrl}->GetValue() );

## Get first terminal in node
    my $terminal = $main_page->{asf}->get_node_terminal($node);

## Get new idle
    my $new_idle = $event->GetString();

## If idle changed
    if ( $terminal and $terminal->{idle} ne $new_idle ) {

## Update idle
        $terminal->{idle} = $new_idle;

## Set XML Updated
        $main_page->{asf}->{updated}++;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_terminal_port_changed()
#
# Event: Right Slave Terminal Port Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_terminal_port_changed {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Get Node
    my $node = $main_page->{asf}->get_machine_node( $slave_page->{machine},
        $slave_page->{node_id_ctrl}->GetValue() );

## Get first terminal in node
    my $terminal = $main_page->{asf}->get_node_terminal($node);

## Get new port
    my $new_port = $event->GetString();

## If port changed
    if ( $terminal and $terminal->{port} ne $new_port ) {

## Update port
        $terminal->{port} = $new_port;

## Set XML Updated
        $main_page->{asf}->{updated}++;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_terminal_separator_changed()
#
# Event: Right Slave Terminal Separator Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_terminal_separator_changed {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Get Node
    my $node = $main_page->{asf}->get_machine_node( $slave_page->{machine},
        $slave_page->{node_id_ctrl}->GetValue() );

## Get first terminal in node
    my $terminal = $main_page->{asf}->get_node_terminal($node);

## Get new separator
    my $new_separator = $event->GetString();

## If separator changed
    if (    $terminal
        and $terminal->{separator}->[0]->{content} ne $new_separator )
    {

## Update separator
        $terminal->{separator}->[0]->{content} = $new_separator;

## Set XML Updated
        $main_page->{asf}->{updated}++;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_terminal_timeout_changed()
#
# Event: Right Slave Terminal Timeout Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_terminal_timeout_changed {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Get Node
    my $node = $main_page->{asf}->get_machine_node( $slave_page->{machine},
        $slave_page->{node_id_ctrl}->GetValue() );

## Get first terminal in node
    my $terminal = $main_page->{asf}->get_node_terminal($node);

## Get new timeout
    my $new_timeout = $event->GetString();

## If timeout changed
    if ( $terminal and $terminal->{timeout} ne $new_timeout ) {

## Update timeout
        $terminal->{timeout} = $new_timeout;

## Set XML Updated
        $main_page->{asf}->{updated}++;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_terminal_whoami_changed()
#
# Event: Right Slave Terminal Whoami Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_terminal_whoami_changed {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Get Node
    my $node = $main_page->{asf}->get_machine_node( $slave_page->{machine},
        $slave_page->{node_id_ctrl}->GetValue() );

## Get first terminal in node
    my $terminal = $main_page->{asf}->get_node_terminal($node);

## Get new whoami
    my $new_whoami = $event->GetString();

## If whoami changed
    if ( $terminal and $terminal->{whoami}->[0]->{content} ne $new_whoami ) {

## Update whoami
        $terminal->{whoami}->[0]->{content} = $new_whoami;

## Set XML Updated
        $main_page->{asf}->{updated}++;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_valid_machine_id_changed()
#
# Event: Right Slave Machine Id Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_valid_machine_id_changed {
    my ( $self, $event ) = @_;

## Set Machine
    $self->set_right_slave_valid_machine( $event->GetString() );

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_master_parse_button()
#
# Event: Right Slave Master Parse Button
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_master_parse_button {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Make content copy for hightlighting
    my $content = $slave_page->{master_ctrl}->GetValue();

## Return Error if no content
    return 0 if !$content;

## Update SMF
    if ( $main_page->{asf}->set_smf($content) ) {

## Set default noprompt mode
        my $noprompt = 1;

## Update ASF using SMF
        $main_page->{asf}->parse_smf($noprompt);

## Set updated state
        $main_page->{asf}->open_xml();

## Save original ASF
        $main_page->{xml_original} = $main_page->{asf}->get_xml();

## Update Source
        $self->set_right_slave_source( $main_page,
            $main_page->{source}->GetReadOnly() );
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_node_id_changed()
#
# Event: Right Slave Node Id Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_node_id_changed {
    my ( $self, $event ) = @_;

## Set Node
    $self->set_right_slave_node( $event->GetString() );

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_node_ip_changed()
#
# Event: Right Slave Node IP Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_node_ip_changed {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Get Node
    my $node = $main_page->{asf}->get_machine_node( $slave_page->{machine},
        $slave_page->{node_id_ctrl}->GetValue() );

## Get new ip
    my $new_ip = $event->GetString();

## If ip changed
    if ( $node and Net::IP::ip_is_ipv4($new_ip) and $node->{ip} ne $new_ip ) {

## Update ip
        $node->{ip} = $new_ip;

## Set XML Updated
        $main_page->{asf}->{updated}++;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_node_terminal_changed()
#
# Event: Right Slave Node Terminal Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_node_terminal_changed {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Get Node
    my $node = $main_page->{asf}->get_machine_node( $slave_page->{machine},
        $slave_page->{node_id_ctrl}->GetValue() );

## Get first terminal in node
    my $terminal = $main_page->{asf}->get_node_terminal($node);

## Get new terminal
    my $new_terminal = $event->GetString();

## If terminal changed
    if ( $terminal and $terminal->{id} ne $new_terminal ) {

## Update terminal
        $terminal->{id} = $new_terminal;

## Set XML Updated
        $main_page->{asf}->{updated}++;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_page_changed()
#
# Event: Right Slave Page Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_page_changed {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );
    my $slave_text = $main_page->GetPageText( $main_page->GetSelection() );

## If only one page opened
    if ( $main_page->GetPageCount() == 1 ) {

## Log Message
        Wx::LogMessage("DEBUG: Only one page opened: $slave_text");

## Set source readonly to False
        $main_page->{source}->SetReadOnly(0);
        $self->set_right_slave_source( $main_page, 0 );

## Change source to RO
        $main_page->SetPageText( $main_page->GetSelection(), "Source" );

## Return Ok
        return 1;
    }

## If source mode disabled
    if ( !$main_page->{source}->GetReadOnly() ) {

## Set source readonly to True
        $main_page->{source}->SetReadOnly(1);
    }
    elsif ( $slave_text =~ "^Source" ) {

## Change source to RO
        $main_page->SetPageText( $main_page->GetSelection(), "Source (R/O)" );
    }

## If it is ATF or ASF Page
    if (   ( $main_page->{atf} and $main_page->{atf}->is_updated() )
        or ( $main_page->{asf} and $main_page->{asf}->is_updated() ) )
    {

## If source page activated
        if ( $slave_text =~ "^Source" ) {

## Log message
            Wx::LogMessage("DEBUG: Source updating while page changing");

## Update source
            $self->set_right_slave_source( $main_page,
                $main_page->{source}->GetReadOnly() );
        }
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_page_close()
#
# Event: Right Slave Page Close
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_page_close {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Return Error If main page wasn't defined
    return 0 if !$main_page;

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );
    my $slave_text = $main_page->GetPageText( $main_page->GetSelection() );

## If it is ATF or ASF Page
    if ( ( $main_page->{atf} or $main_page->{asf} )
        and $slave_text =~ "^Source" )
    {

## Log Message
        Wx::LogMessage("DEBUG: Source Reopened");

## Delete old source
        delete( $main_page->{source} );

## Reopen Source
        $self->set_right_slave_source( $main_page, 0 );

## Add page to notebook
        $main_page->AddPage( $main_page->{source}, "Source", 0 );
    }

## If it is ASF Page for RCmd
    if ( ( $main_page->{asf} or $main_page->{asf} )
        and $slave_text =~ "^RCmd" )
    {

## Log Message
        Wx::LogMessage("DEBUG: RCmd closed");

## Destroy ARF
        $slave_page->{arf}->DESTROY() if $slave_page->{arf};
    }

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_param_id_changed()
#
# Event: Right Slave Parameter Id Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_param_id_changed {
    my ( $self, $event ) = @_;

## Set Parameter
    $self->set_right_slave_param( $event->GetString() );

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_rcmd_execute_button()
#
# Event: Right Slave RCmd Execute Button
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_rcmd_execute_button {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Get Input Command
    my $rcmd = $slave_page->{rcmd_input_ctrl}->GetValue();

## Return Error if no rcmd
    return 0 if !$rcmd;

## Define End
    my $scenario;

## Execute RCmd
    my $output =
      $slave_page->{process}
      ->execute_rcmd( $slave_page->{arf}, $slave_page->{step_id},
        $slave_page->{login}, $rcmd, $scenario );
    $slave_page->{rcmd_output_ctrl}->AppendText($output);

## Increment Step
    $slave_page->{step_id}++;

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_rcmd_run_scenario_button()
#
# Event: Right Slave RCmd Run Scenario Button
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_rcmd_run_scenario_button {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Return Error if no scenario
    return 0 if !$slave_page->{scenario};

## Get Step
    my $step_id = $slave_page->{scenario_step_ctrl}->GetValue();

## Return Error if no step
    return 0 if !$step_id;

## Execute RCmd
    my $output =
      $slave_page->{process}
      ->execute_rcmd( $slave_page->{arf}, $slave_page->{step_id},
        $slave_page->{login}, $step_id, $slave_page->{scenario} );
    $slave_page->{rcmd_output_ctrl}->AppendText($output);

## Increment Step
    $slave_page->{step_id}++;

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_refer_changed()
#
# Event: Right Slave Referrer Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_refer_changed {
    my ( $self, $event ) = @_;

## Set Referrer
    $self->set_right_slave_refer( $event->GetString() );

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_static_check_button()
#
# Event: Right Slave Static Check Button
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_static_check_button {
    my ( $self, $event ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Make content copy for hightlighting
    my $content = $slave_page->{static_ctrl}->GetValue();

## Return Error if no content
    return 0 if !$content;

## Save static's content
    $main_page->{atf}->set_static( $slave_page->{step}->{id}, $content );

## Parameters parsing in Step
    foreach my $param ( @{ $slave_page->{step}->{param} } ) {

## Set param's color
        my $font_color = "green";

## Check step's static
        my ( $value, $param_static ) = eval {
            $self->{ARF}->check_step_static( $content, $param->{method},
                $param->{content} );
        };

## Set failed param's color if value failed
        $font_color = "red" if !$value;

## Find parameter's content
        $content =~ /$param->{content}/;

## Set parameter's content
        my $param_content = $&;

## If static found
        if ($param_static) {

## Hightlight value
            eval {
                $param_content =~
                  s/\Q$param_static\E/<font color=orange>$&<\/font>/;
            };
        }

## Hightlight parameters
        eval {
            $content =~
s/$param->{content}/<font color="$font_color">$param_content<\/font>/;
        };
    }

## Add static in XHTML
    my $html = "<pre>$content</pre>";
    $slave_page->{static_html}->SetPage($html);

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_scenario_id_changed()
#
# Event: Right Slave Scenario Id Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_scenario_id_changed {
    my ( $self, $event ) = @_;

## Set Scenario
    $self->set_right_slave_scenario( $event->GetString() );

## Return Ok
    return 1;
}

##############################################################################
#
# on_right_slave_source_changed()
#
# Event: Right Slave Source Changed
#
# Arguments expected are:
# - self          - Object reference
# - event         - Event Object

sub on_right_slave_source_changed {
    my ( $self, $event ) = @_;

## Get Right notebook
    my $right_nb = $self->{right_nb};

## Get selected page
    my $main_page = $right_nb->GetPage( $right_nb->GetSelection() );

## Return Error if ATF wasn't specified
    return 0 if !$main_page;

## Define text and type
    my ( $main_text, $type );

## If ATF/STF sourced
    if ( $main_page->{atf} ) {

## Get ATF/STF text and source type
        $main_text = $main_page->{atf}->get_id();
        $type      = $main_page->{xml_type};
    }

## If ASF sourced
    if ( $main_page->{asf} ) {

## Get ATF/STF text and source type
        $main_text = $main_page->{asf}->get_id();
        $type      = 'Site';
    }

## Get Source
    my $source = $main_page->{source}->GetText();

## Return Ok if source was deleted
    return 1 if !$source;

## if Text wasn't changed
    if ( $source eq $main_page->{xml_original} ) {

## Update main page
        $right_nb->SetPageText( $right_nb->GetSelection(), "$type:$main_text" );

## Set updated state
        $main_page->{atf}->{updated} = 0 if $main_page->{atf};
        $main_page->{asf}->{updated} = 0 if $main_page->{asf};

## Delete All Markers
        $main_page->{source}->MarkerDeleteAll(1);

## Return Ok
        return 1;
    }

## Log Message
    Wx::LogMessage('DEBUG: Source difference found');

## Update main page
    $right_nb->SetPageText( $right_nb->GetSelection(), "*$type:$main_text" );

## Get sequences from source
    my @seq1 = split( "\n", $source );
    my @seq2 = split( "\n", $main_page->{xml_original} );

## Marker difference
    Algorithm::Diff::traverse_sequences(
        \@seq1,
        \@seq2,
        {
            MATCH => sub { $main_page->{source}->MarkerDelete( $_[0], 1 ); },
            DISCARD_A => sub { $main_page->{source}->MarkerAdd( $_[0], 1 ); },
        }
    );

## Set updated state
    $main_page->{atf}->{updated}++ if $main_page->{atf};
    $main_page->{asf}->{updated}++ if $main_page->{asf};

## Return Ok
    return 1;
}

##############################################################################
#
# set_frame()
#
# Set Frame
#
# Arguments expected are:
# - self          - Object reference

sub set_frame {
    my ($self) = @_;

## Create Left Splitter
    my $main_split = Wx::SplitterWindow->new( $self, -1 );

## Create Left Splitter
    my $left_split = Wx::SplitterWindow->new( $main_split, -1 );

## Create Right Splitter
    my $right_split = Wx::SplitterWindow->new( $main_split, -1 );

## Add notebook into Left Splitter
    $self->{left_nb} =
      Wx::AuiNotebook->new( $left_split, -1, wxDefaultPosition, wxDefaultSize,
        wxAUI_NB_DEFAULT_STYLE );

## Add notebook into Right Splitter
    $self->{right_nb} =
      Wx::AuiNotebook->new( $right_split, -1, wxDefaultPosition, wxDefaultSize,
        wxAUI_NB_DEFAULT_STYLE );

## Add Opened into Left
    $self->{opened} =
      Wx::TreeCtrl->new( $left_split, -1, wxDefaultPosition, wxDefaultSize,
        wxTR_DEFAULT_STYLE );

## Set Opened Root
    $self->{opened_root} =
      $self->{opened}
      ->AddRoot( "Nothing selected", -1, -1, Wx::TreeItemData->new('Opened') );

## Add Log Text
    my $text_log = Wx::TextCtrl->new(
        $right_split, -1, "Welcome to $self->{title} $self->{version}\n",
        wxDefaultPosition,
        [ -1, 100 ],
        wxTE_READONLY | wxTE_MULTILINE
    );

## Set Log
    my $log = Wx::LogTextCtrl->new($text_log);
    $self->{OLDLOG} = Wx::Log::SetActiveTarget($log);

## Split left splitter vertically
    $main_split->SplitVertically( $left_split, $right_split, 250 );
    $left_split->SplitHorizontally( $self->{left_nb}, $self->{opened}, 300 );
    $right_split->SplitHorizontally( $self->{right_nb}, $text_log, -100 );

## Set Site Tree
    $self->set_left_site_page();

## Set Left Notebook Events
    Wx::Event::EVT_AUINOTEBOOK_PAGE_CLOSE( $self, $self->{left_nb},
        \&on_left_page_close );

## Set Right Notebook Events
    Wx::Event::EVT_AUINOTEBOOK_PAGE_CLOSE( $self, $self->{right_nb},
        \&on_right_main_page_close );
    Wx::Event::EVT_AUINOTEBOOK_PAGE_CHANGED( $self, $self->{right_nb},
        \&on_right_main_page_changed );

## Set Opened Tree Events
    Wx::Event::EVT_TREE_ITEM_ACTIVATED( $self, $self->{opened},
        \&on_left_opened_activated );
    Wx::Event::EVT_TREE_ITEM_MENU( $self, $self->{opened},
        \&on_left_opened_menu );

## Set Frame Events
    Wx::Event::EVT_CLOSE( $self, \&on_frame_close );

## Return Ok
    return 1;
}

##############################################################################
#
# set_left_atf_page()
#
# Populate Templates into Tree
#
# Arguments expected are:
# - self          - Object reference

sub set_left_atf_page {
    my ($self) = @_;

## Define page's title
    my $page_text = 'Template';

## Get Left Notebook
    my $left_nb = $self->{left_nb};

## Check all pages
    foreach my $page_num ( 0 .. $left_nb->GetPageCount() ) {

## Skip if page not equal template
        next if $left_nb->GetPageText($page_num) ne $page_text;

## Select already opened page
        $left_nb->SetSelection($page_num);

## Return Error
        return 0;
    }

    $self->{atf_page} =
      Wx::TreeCtrl->new( $left_nb, -1, wxDefaultPosition, wxDefaultSize,
        wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT );
    $left_nb->AddPage( $self->{atf_page}, $page_text, 1 );

## Set ATF Tree Events
    Wx::Event::EVT_TREE_ITEM_ACTIVATED( $self, $self->{atf_page},
        \&on_left_atf_page_activated );
    Wx::Event::EVT_TREE_ITEM_EXPANDING( $self, $self->{atf_page},
        \&on_left_atf_page_expanding );
    Wx::Event::EVT_TREE_ITEM_MENU( $self, $self->{atf_page},
        \&on_left_atf_page_menu );

## Set Templates Root
    my $atf_root =
      $self->{atf_page}
      ->AddRoot( $page_text, -1, -1, Wx::TreeItemData->new($page_text) );

## Retrieve ACF machines
    my $acf_machines = $self->{Process}->{ACF}->get_list_machine();

## If machines exist in ACF
    if ( !$acf_machines ) {

## Add item into root
        my $item =
          $self->{atf_page}
          ->AppendItem( $atf_root, 'N/A', 0, 1, Wx::TreeItemData->new('N/A') );

## Expand Tree
        $self->{atf_page}->Expand($atf_root);

## Return Error
        return 0;
    }

## Check machines in ACF
    foreach my $machine ( @{$acf_machines} ) {

## Get Template Id
        my $template_id = $machine->{template}->[0]->{id};

## Skip wrong machine
        next if !$template_id;

## Open ATF
        my $atf = new AFX::ATF( $self->{ARF}, $template_id, 'template' );

## Set Machines Units
        my $atf_machines = "";

## Check Machines in template
        foreach my $machine ( @{ $atf->{_xml}->{machine} } ) {

## Add machine
            $atf_machines .= ", " if $atf_machines;
            $atf_machines .= $machine->{id};
        }

## Add item into root
        my $item = $self->{atf_page}->AppendItem(
            $atf_root,
            "$atf->{id} ("
              . $atf->get_version() . ", "
              . $atf->get_type()
              . ") [$atf_machines]",
            0,
            1,
            Wx::TreeItemData->new($template_id)
        ) if $atf;

## Add item into template
        $self->{atf_page}
          ->AppendItem( $item, "...", 0, 1, Wx::TreeItemData->new("...") )
          if $item;
    }

## Sort Children
    $self->{atf_page}->SortChildren($atf_root);

## Expand Tree
    $self->{atf_page}->Expand($atf_root);

## Return Ok
    return 1;
}

##############################################################################
#
# set_left_opened_tree()
#
# Set Opened Tree
#
# Arguments expected are:
# - self          - Object reference
# - page          - WxStyledTreeCtrl Object

sub set_left_opened_tree {
    my ( $self, $main_page ) = @_;

## Return Error if opened root wasn't definer
    return 0 if !$self->{opened} or !$self->{opened_root};

## Delete all childrens
    $self->{opened}->DeleteChildren( $self->{opened_root} );

## If page not specified
    if ( !$main_page ) {

## Set New Item's Text
        $self->{opened}
          ->SetItemText( $self->{opened_root}, "Nothing selected" );

## Return Ok
        return 1;
    }

## If ATF opened
    if ( $main_page->{atf} and $main_page->{atf}->{_xml} ) {

## Set New Item's Text
        $self->{opened}
          ->SetItemText( $self->{opened_root}, $main_page->{atf}->get_id() );

## Check steps in ATF
        foreach my $step ( @{ $main_page->{atf}->{_xml}->{step} } ) {

## Add opened
            $self->{opened}
              ->AppendItem( $self->{opened_root}, $step->{id}, 0, 1,
                Wx::TreeItemData->new( $step->{id} ) );
        }
    }

## If ASF opened
    if ( $main_page->{asf} and $main_page->{asf}->{_xml} ) {

## Set New Item's Text
        $self->{opened}
          ->SetItemText( $self->{opened_root}, $main_page->{asf}->get_id() );

## Retrieve ACF machines
        my $acf_machines = $self->{Process}->{ACF}->get_list_machine();

## If machines exist in ACF
        if ( !$acf_machines ) {

## Add item into root
            my $item =
              $self->{opened}->AppendItem( $self->{opened_root}, 'N/A', 0, 1,
                Wx::TreeItemData->new('N/A') );

## Expand Tree
            $self->{opened}->Expand( $self->{opened_root} );

## Return Error
            return 0;
        }

## Check machines in ACF
        foreach my $machine ( @{$acf_machines} ) {

## Skip empty units
            next if !$main_page->{asf}->get_list_machine( $machine->{id} );

## Add opened
            my $item =
              $self->{opened}
              ->AppendItem( $self->{opened_root}, $machine->{id}, 0, 1,
                Wx::TreeItemData->new( $machine->{id} ) );

## Check machines in ASF
            foreach
              my $asf_machine ( @{ $main_page->{asf}->{_xml}->{machine} } )
            {

## Skip wrong units
                next if $asf_machine->{unit} ne $machine->{id};

## Add ASF machine
                $self->{opened}->AppendItem( $item, $asf_machine->{id}, 0, 1,
                    Wx::TreeItemData->new( $asf_machine->{id} ) );
            }
        }
    }

## Expand Tree
    $self->{opened}->Expand( $self->{opened_root} );

## Return Ok
    return 1;
}

##############################################################################
#
# set_left_site_page()
#
# Populate Sites into Tree
#
# Arguments expected are:
# - self          - Object reference

sub set_left_site_page {
    my ($self) = @_;

## Define page's title
    my $page_text = 'Site';

## Get Left Notebook
    my $left_nb = $self->{left_nb};

## Check all pages
    foreach my $page_num ( 0 .. $left_nb->GetPageCount() ) {

## Skip if page not equal template
        next if $left_nb->GetPageText($page_num) ne $page_text;

## Select already opened page
        $left_nb->SetSelection($page_num);
    }

## If site page wasn't defined
    if ( !$self->{site_page} ) {

## Add Site into Left Notebook
        $self->{site_page} =
          Wx::TreeCtrl->new( $left_nb, -1, wxDefaultPosition, wxDefaultSize,
            wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT );
        $left_nb->AddPage( $self->{site_page}, $page_text, 1 );

## Set STF Tree Events
        Wx::Event::EVT_TREE_ITEM_ACTIVATED( $self, $self->{site_page},
            \&on_left_site_page_activated );
        Wx::Event::EVT_TREE_ITEM_MENU( $self, $self->{site_page},
            \&on_left_site_page_menu );

## Set Site Root
        $self->{site_root} =
          $self->{site_page}
          ->AddRoot( $page_text, -1, -1, Wx::TreeItemData->new($page_text) );
    }

## Delete all childrens
    $self->{site_page}->DeleteChildren( $self->{site_root} );

## Find ASF
    my $asfnames = $self->{Process}->{ACF}->find_asf();

## If no Site found
    if ( !$asfnames ) {

## Add item into root
        my $item =
          $self->{site_page}->AppendItem( $self->{site_root}, 'N/A', 0, 1,
            Wx::TreeItemData->new('N/A') );

## Expand Tree
        $self->{site_page}->Expand( $self->{site_root} );

## Return Error
        return 0;
    }

## Check templates
    foreach my $asfname ( @{$asfnames} ) {

## Open ASF
        my $asf = new AFX::ASF( $self->{Process}->{ACF}, $asfname );

## Add item into root
        my $item =
          $self->{site_page}->AppendItem( $self->{site_root}, $asf->{id}, 0, 1,
            Wx::TreeItemData->new( $asf->{id} ) )
          if $asf;
    }

## Sort Children
    $self->{site_page}->SortChildren( $self->{site_root} );

## Expand Tree
    $self->{site_page}->Expand( $self->{site_root} );

## Return Ok
    return 1;
}

##############################################################################
#
# set_left_stf_page()
#
# Populate Scenarios into Tree
#
# Arguments expected are:
# - self          - Object reference

sub set_left_stf_page {
    my ($self) = @_;

## Define page's title
    my $page_text = 'Scenario';

## Get Left Notebook
    my $left_nb = $self->{left_nb};

## Check all pages
    foreach my $page_num ( 0 .. $left_nb->GetPageCount() ) {

## Skip if page not equal template
        next if $left_nb->GetPageText($page_num) ne $page_text;

## Select already opened page
        $left_nb->SetSelection($page_num);

## Return Error
        return 0;
    }

## Add Scenario into Left Notebook
    $self->{stf_page} =
      Wx::TreeCtrl->new( $left_nb, -1, wxDefaultPosition, wxDefaultSize,
        wxTR_DEFAULT_STYLE | wxTR_HIDE_ROOT );
    $left_nb->AddPage( $self->{stf_page}, $page_text, 1 );

## Set STF Tree Events
    Wx::Event::EVT_TREE_ITEM_ACTIVATED( $self, $self->{stf_page},
        \&on_left_stf_page_activated );
    Wx::Event::EVT_TREE_ITEM_MENU( $self, $self->{stf_page},
        \&on_left_stf_page_menu );

## Set Scenario Root
    my $stf_root =
      $self->{stf_page}
      ->AddRoot( $page_text, -1, -1, Wx::TreeItemData->new($page_text) );

## Find STF
    my $stfnames = $self->{Process}->{ACF}->find_atf( 'scenario', "" );

## If machines exist in ACF
    if ( !$stfnames ) {

## Add item into root
        my $item =
          $self->{stf_page}
          ->AppendItem( $stf_root, 'N/A', 0, 1, Wx::TreeItemData->new('N/A') );

## Expand Tree
        $self->{stf_page}->Expand($stf_root);

## Return Error
        return 0;
    }

## Check templates
    foreach my $stfname ( @{$stfnames} ) {

## Open ATF
        my $stf = new AFX::ATF( $self->{ARF}, $stfname, 'scenario' );

## Add item into root
        my $item =
          $self->{stf_page}
          ->AppendItem( $stf_root, "$stf->{id} [" . $stf->get_type() . "]",
            0, 1, Wx::TreeItemData->new( $stf->{id} ) )
          if $stf;
    }

## Sort Children
    $self->{stf_page}->SortChildren($stf_root);

## Expand Tree
    $self->{stf_page}->Expand($stf_root);

## Return Ok
    return 1;
}

##############################################################################
#
# set_menubar()
#
# Set Frame's Menubar
#
# Arguments expected are:
# - self          - Object reference

sub set_menubar {
    my ($self) = @_;

## Create Menubar
    my $bar = Wx::MenuBar->new();
    $self->SetMenuBar($bar);

## Create File menu
    my $file = Wx::Menu->new();
    $file->Append( wxID_EXIT, "E&xit" );

## Set File Menu Events
    Wx::Event::EVT_MENU( $self, wxID_EXIT, sub { $self->Close() } );

## Create View menu
    my $view        = Wx::Menu->new();
    my $ID_TEMPLATE = Wx::NewId();
    my $ID_SCENARIO = Wx::NewId();
    my $ID_SITE     = Wx::NewId();

    Wx::Event::EVT_MENU(
        $self,
        $view->Append( -1, "&Site" ),
        sub { $self->set_left_site_page(); }
    );
    $view->AppendSeparator();

## Add Templates and Scenarios
    Wx::Event::EVT_MENU(
        $self,
        $view->Append( -1, "&Template" ),
        sub { $self->set_left_atf_page(); }
    );
    Wx::Event::EVT_MENU(
        $self,
        $view->Append( -1, "&Scenario" ),
        sub { $self->set_left_stf_page(); }
    );

## Create Help menu
    my $help = Wx::Menu->new();
    $help->Append( wxID_ABOUT, "&About" );

## Set Help  Menu Events
    Wx::Event::EVT_MENU( $self, wxID_ABOUT, \&show_about );

## Fill menu
    $bar->Append( $file, "&File" );
    $bar->Append( $view, "&View" );
    $bar->Append( $help, "&Help" );

## Return Ok
    return 1;
}

##############################################################################
#
# set_right_main_xml()
#
# Set Right XML
#
# Arguments expected are:
# - self          - Object reference
# - main_page     - wxAuiNotebook

sub set_right_main_xml {
    my ( $self, $main_page ) = @_;

## Return Error if source not defined
    return 0 if !$main_page or !$main_page->{source};

## Get Source
    my $source = $main_page->{source}->GetText();

## Update ATF XML
    my $xml_updated = $main_page->{atf}->set_xml($source)
      if $main_page->{atf} and $source;

## Update ASF XML
    my $xml_updated = $main_page->{asf}->set_xml($source)
      if $main_page->{asf} and $source;

## Return Ok
    return 1;
}

##############################################################################
#
# set_right_slave_command()
#
# Set Right Slave Command
#
# Arguments expected are:
# - self          - Object reference

sub set_right_slave_command {
    my ($self) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Return Error if slave page not selected
    return 0
      if !$slave_page
          or !$slave_page->{step}
          or !$slave_page->{command_login_ctrl};

## Clear and Append all logins items
    $slave_page->{command_login_ctrl}->Clear();

## Retrieve ACF machines
    my $atf_machines = $main_page->{atf}->get_list_machine();

## Retrieve ACF passwords
    my $acf_passwords = $self->{Process}->{ACF}->get_list_passwd();

## Define logins
    my @logins;

## Check machines in ACF
    foreach my $machine ( @{$atf_machines} ) {

## Check passwd for unit in ACF
        foreach my $passwd ( @{$acf_passwords} ) {

## Skip wrong passwd
            next
              if !$passwd->{unit}
                  or $passwd->{unit} ne $machine->{unit};
            next if !$passwd->{login};

## Skip if login already in array
            next if ( grep { $_ eq $passwd->{login} } @logins );

## Add login into array
            $slave_page->{command_login_ctrl}->Append( $passwd->{login} );
            push( @logins, $passwd->{login} );
        }
    }

## Set Command Hint
    my $hint = $self->{ARF}->get_step_hint( $slave_page->{step} );

    if ( !$hint ) {

## Add step
        $self->{ARF}->add_step_hint( $slave_page->{step}, "", "", "", "" );
    }
    else {

## Update Hint Control
        $slave_page->{hint_ctrl}->SetValue( $hint->{content} );
    }

## Set static
    $slave_page->{static_ctrl}
      ->SetValue( $main_page->{atf}->get_static( $slave_page->{step}->{id} ) );

## Get first command
    my $command = $slave_page->{step}->{command}->[0]
      if $slave_page->{step}->{command};

## If command doesn't exist
    if ( !$command ) {

## Add command
        $self->{ARF}->add_step_command( $slave_page->{step}, "", "", "" );
    }

## Clear and Append all check items
    $slave_page->{command_passwd_ctrl}->Clear();
    foreach my $argument ( @{ $main_page->{atf}->{_xml}->{argument} } ) {
        next if !$argument->{id} or !$argument->{login};
        $slave_page->{command_passwd_ctrl}->Append( $argument->{id} );
    }

## Set Command Attributes
    $slave_page->{command_content_ctrl}->SetValue( $command->{content} );
    $slave_page->{command_login_ctrl}->SetValue( $command->{login} );
    $slave_page->{command_remote_ctrl}->SetValue( $command->{remote} );
    $slave_page->{command_end_ctrl}->SetValue( $command->{end} );
    $slave_page->{command_timeout_ctrl}->SetValue( $command->{timeout} );
    $slave_page->{command_passwd_ctrl}->SetValue( $command->{passwd} );

## Return Ok
    return 1;
}

##############################################################################
#
# set_right_slave_layout()
#
# Set Right Slave Layout
#
# Arguments expected are:
# - self          - Object reference

sub set_right_slave_layout {
    my ($self) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Update Vrtual Size
    $slave_page->FitInside();

## Update Main page
    $main_page->Layout();

## Return Ok
    return 1;
}

##############################################################################
#
# set_right_slave_valid_machine()
#
# Set Right Slave Machine
#
# Arguments expected are:
# - self          - Object reference
# - machine_id    - Machine's Identifier

sub set_right_slave_valid_machine {
    my ( $self, $machine_id ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Return Error if slave page not selected
    return 0
      if !$slave_page
          or !$slave_page->{machine_id_ctrl};

## Get Parameter
    my $machine = $main_page->{atf}->get_machine($machine_id);

## If parameter doesn't exist
    if ( !$machine ) {

## Log Message
        Wx::LogMessage("Machine $machine_id doesn't exist");

## Return Error
        return 0;
    }

## Return Ok
    return 1;
}

##############################################################################
#
# set_right_slave_page_machine()
#
# Open ASF Machine for Design
#
# Arguments expected are:
# - self          - Object reference
# - mach_id       - Machine's Identifier
# - mach_unit     - Machine's Unit

sub set_right_slave_page_machine {
    my ( $self, $mach_id, $mach_unit ) = @_;

    use Wx qw(wxTE_MULTILINE wxHORIZONTAL wxVERTICAL wxALL wxEXPAND
      wxCENTRE);

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Check all pages
    foreach my $page_num ( 0 .. $main_page->GetPageCount() ) {

## Skip if page not equal template
        next if $main_page->GetPageText($page_num) ne $mach_id;

## Select already opened page
        $main_page->SetSelection($page_num);

## Return Error
        return 0;
    }

## Get Machine
    my $machine = $main_page->{asf}->get_machine( $mach_id, $mach_unit );

## Return Error if machine not found
    return 0 if !$machine;

## Add New Machine into Right Notebook
    my $panel = Wx::ScrolledWindow->new( $self->{right_nb}, -1 );

## Set Machine to panel
    $panel->{machine} = $machine;

## Add page to notebook
    $main_page->AddPage( $panel, $mach_id, 1 );

## Main sizer
    my $main_sizer = Wx::BoxSizer->new(wxVERTICAL);
    $panel->SetSizerAndFit($main_sizer);
    $panel->SetScrollRate( 1, 1 );

## Add node static box
    my $node_sizer =
      Wx::StaticBoxSizer->new( Wx::StaticBox->new( $panel, -1, "&Node" ),
        wxVERTICAL );
    $main_sizer->Add( $node_sizer, 0, wxEXPAND );

## Add Node Id sizer
    my $node_id_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $node_sizer->Add( $node_id_sizer, 0, wxALL, 2 );

## Add Node Id into sizer
    $node_id_sizer->Add( Wx::StaticText->new( $panel, -1, "Host: " ),
        0, wxCENTRE );
    $panel->{node_id_ctrl} = Wx::ComboBox->new( $panel, -1 );
    $node_id_sizer->Add( $panel->{node_id_ctrl}, 0, wxALL );

## Set Machine Id Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{node_id_ctrl},
        \&on_right_slave_node_id_changed
    );

## Add Node Attr into sizer
    my $node_attr_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $node_sizer->Add( $node_attr_sizer, 0, wxALL, 2 );

## Add Node IP into sizer
    $node_attr_sizer->Add( Wx::StaticText->new( $panel, -1, "IP: " ),
        0, wxCENTRE );
    $panel->{node_ip_ctrl} =
      Wx::TextCtrl->new( $panel, -1, "", wxDefaultPosition, [ 140, -1 ] );
    $node_attr_sizer->Add( $panel->{node_ip_ctrl}, 0, wxALL );

## Set Node IP Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{node_ip_ctrl},
        \&on_right_slave_node_ip_changed
    );

## Add Node Terminal into sizer
    $node_attr_sizer->Add( Wx::StaticText->new( $panel, -1, " Terminal: " ),
        0, wxCENTRE );
    $panel->{node_terminal_ctrl} = Wx::ComboBox->new( $panel, -1 );
    $node_attr_sizer->Add( $panel->{node_terminal_ctrl}, 0, wxALL );

## Set Node IP Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{node_terminal_ctrl},
        \&on_right_slave_node_terminal_changed
    );

## Add terminal static box
    my $terminal_sizer =
      Wx::StaticBoxSizer->new( Wx::StaticBox->new( $panel, -1, "&Terminal" ),
        wxVERTICAL );
    $node_sizer->Add( $terminal_sizer, 0, wxEXPAND );

## Add Terminal Attr into sizer
    my $terminal_attr_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $terminal_sizer->Add( $terminal_attr_sizer, 0, wxALL, 2 );

## Add Terminal Port into sizer
    $terminal_attr_sizer->Add( Wx::StaticText->new( $panel, -1, "Port: " ),
        0, wxCENTRE );
    $panel->{terminal_port_ctrl} = Wx::TextCtrl->new( $panel, -1, "" );
    $terminal_attr_sizer->Add( $panel->{terminal_port_ctrl}, 0, wxALL );

## Set Node IP Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{terminal_port_ctrl},
        \&on_right_slave_terminal_port_changed
    );

## Add Terminal Timeout into sizer
    $terminal_attr_sizer->Add( Wx::StaticText->new( $panel, -1, " Timeout: " ),
        0, wxCENTRE );
    $panel->{terminal_timeout_ctrl} = Wx::TextCtrl->new( $panel, -1, "" );
    $terminal_attr_sizer->Add( $panel->{terminal_timeout_ctrl}, 0, wxALL );

## Set Node IP Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{terminal_timeout_ctrl},
        \&on_right_slave_terminal_timeout_changed
    );

## Add Terminal Idle into sizer
    $terminal_attr_sizer->Add( Wx::StaticText->new( $panel, -1, " Idle: " ),
        0, wxCENTRE );
    $panel->{terminal_idle_ctrl} = Wx::TextCtrl->new( $panel, -1, "" );
    $terminal_attr_sizer->Add( $panel->{terminal_idle_ctrl}, 0, wxALL );

## Set Node IP Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{terminal_idle_ctrl},
        \&on_right_slave_terminal_idle_changed
    );

## Add Terminal Attr2 into sizer
    my $terminal_attr2_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $terminal_sizer->Add( $terminal_attr2_sizer, 0, wxALL, 2 );

## Add Terminal Whoami into sizer
    $terminal_attr2_sizer->Add( Wx::StaticText->new( $panel, -1, "Whoami: " ),
        0, wxCENTRE );
    $panel->{terminal_whoami_ctrl} =
      Wx::TextCtrl->new( $panel, -1, "", wxDefaultPosition, [ 140, -1 ] );
    $terminal_attr2_sizer->Add( $panel->{terminal_whoami_ctrl}, 0, wxALL );

## Set Node IP Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{terminal_whoami_ctrl},
        \&on_right_slave_terminal_whoami_changed
    );

## Add Terminal Separator into sizer
    $terminal_attr2_sizer->Add(
        Wx::StaticText->new( $panel, -1, " Separator: " ),
        0, wxCENTRE );
    $panel->{terminal_separator_ctrl} =
      Wx::TextCtrl->new( $panel, -1, "", wxDefaultPosition, [ 140, -1 ] );
    $terminal_attr2_sizer->Add( $panel->{terminal_separator_ctrl}, 0, wxALL );

## Set Node IP Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{terminal_separator_ctrl},
        \&on_right_slave_terminal_separator_changed
    );

## Check all nodes in machine
    my @nodes;
    foreach my $node ( @{ $machine->{node} } ) {
        next if !$node->{host};
        push( @nodes, $node->{host} );
        $panel->{node_id_ctrl}->Append( $node->{host} );
    }

## If nodes specified
    if ( @nodes and $nodes[0] ) {

## Set first node
        $panel->{node_id_ctrl}->SetValue( $nodes[0] );
        $self->set_right_slave_node( $nodes[0] );
    }

## Page Layout
    $self->set_right_slave_layout();

## Return Ok
    return 1;
}

##############################################################################
#
# set_right_slave_page_master()
#
# Open ATF Machine for Design
#
# Arguments expected are:
# - self          - Object reference
# - site_id       - Site's Identifier

sub set_right_slave_page_master {
    my ( $self, $site_id ) = @_;

    use Wx qw(wxTE_MULTILINE wxHORIZONTAL wxVERTICAL wxALL wxEXPAND
      wxCENTRE wxTELETYPE wxNORMAL);

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Set page text
    my $page_text = 'Master';

## Check all pages
    foreach my $page_num ( 0 .. $main_page->GetPageCount() ) {

## Skip if page not equal template
        next if $main_page->GetPageText($page_num) ne $page_text;

## Select already opened page
        $main_page->SetSelection($page_num);

## Return Error
        return 0;
    }

## Return Error if machine not found
    return 0 if $main_page->{asf}->get_id() ne $site_id;

## Add New Machine into Right Notebook
    my $panel = Wx::ScrolledWindow->new( $self->{right_nb}, -1 );

## Add page to notebook
    $main_page->AddPage( $panel, $page_text, 1 );

## Main sizer
    my $main_sizer = Wx::BoxSizer->new(wxVERTICAL);
    $panel->SetSizerAndFit($main_sizer);
    $panel->SetScrollRate( 1, 1 );

## Add Master into sizer
    $panel->{master_ctrl} =
      new Wx::TextCtrl( $panel, -1, "", wxDefaultPosition, wxDefaultSize,
        wxTE_MULTILINE );
    $main_sizer->Add( $panel->{master_ctrl}, 1, wxALL | wxEXPAND, 2 );
    $panel->{master_ctrl}
      ->SetFont( Wx::Font->new( 10, wxTELETYPE, wxNORMAL, wxNORMAL ) );

## Set Master
    $panel->{master_ctrl}->SetValue( $main_page->{asf}->open_smf() );

## Add Parse Master button
    my $parse_master = Wx::Button->new( $panel, -1, 'Parse and save master' );
    $main_sizer->Add( $parse_master, 0, wxALL, 2 );
    Wx::Event::EVT_BUTTON( $self, $parse_master,
        \&on_right_slave_master_parse_button );

## Page Layout
    $self->set_right_slave_layout();

## Return Ok
    return 1;
}

##############################################################################
#
# set_right_slave_node()
#
# Set Right Slave node
#
# Arguments expected are:
# - self          - Object reference
# - node_id       - Node's Identifier

sub set_right_slave_node {
    my ( $self, $node_id ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Return Error if slave page not selected
    return 0
      if !$slave_page
          or !$slave_page->{node_id_ctrl};

## Get Node
    my $node =
      $main_page->{asf}->get_machine_node( $slave_page->{machine}, $node_id );

## If node doesn't exist
    if ( !$node ) {

## Log Message
        Wx::LogMessage("Node $node_id doesn't exist");

## Return Error
        return 0;
    }

## Clear and Append all terminal items
    my @node_terminal = ( "telnet", "ssh", "dumb", "auto" );
    $slave_page->{node_terminal_ctrl}->Clear();
    foreach my $item (@node_terminal) {
        $slave_page->{node_terminal_ctrl}->Append($item);
    }

## Get first terminal in node
    my $terminal = $main_page->{asf}->get_node_terminal($node);

## If terminal wasn't specified
    if ( !$terminal ) {
        $terminal =
          $main_page->{asf}->add_node_terminal( $node, $node_terminal[0] );
    }

## Set Node Attributes
    $slave_page->{node_ip_ctrl}->SetValue( $node->{ip} );
    $slave_page->{node_terminal_ctrl}->SetValue( $terminal->{id} );

## Set Terminal Attributes
    $slave_page->{terminal_port_ctrl}->SetValue( $terminal->{port} );
    $slave_page->{terminal_timeout_ctrl}->SetValue( $terminal->{timeout} );
    $slave_page->{terminal_idle_ctrl}->SetValue( $terminal->{idle} );
    $slave_page->{terminal_separator_ctrl}
      ->SetValue( $terminal->{separator}->[0]->{content} );
    $slave_page->{terminal_whoami_ctrl}
      ->SetValue( $terminal->{whoami}->[0]->{content} );

## Return Ok
    return 1;
}

##############################################################################
#
# set_right_slave_param()
#
# Set Right Slave Parameter
#
# Arguments expected are:
# - self          - Object reference
# - param_id      - Parameter's Identifier

sub set_right_slave_param {
    my ( $self, $param_id ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Return Error if slave page not selected
    return 0
      if !$slave_page
          or !$slave_page->{step}
          or !$slave_page->{param_id_ctrl};

## Get Parameter
    my $param =
      $main_page->{atf}->get_step_param( $slave_page->{step}, $param_id );

## If parameter doesn't exist
    if ( !$param ) {

## Log Message
        Wx::LogMessage("Parameter $param_id doesn't exist");

## Return Error
        return 0;
    }

## Clear and Append all methods items
    my @param_method = ( "=~", "!~" );
    $slave_page->{param_method_ctrl}->Clear();
    foreach my $item (@param_method) {
        $slave_page->{param_method_ctrl}->Append($item);
    }

## Clear and Append all severity items
    my @param_severity = ( "", "critical", "major", "minor", "refer" );
    $slave_page->{param_severity_ctrl}->Clear();
    foreach my $item (@param_severity) {
        $slave_page->{param_severity_ctrl}->Append($item);
    }

## Clear and Append all compare items
    my @param_compare = ( "", "node" );
    $slave_page->{param_compare_ctrl}->Clear();
    foreach my $item (@param_compare) {
        $slave_page->{param_compare_ctrl}->Append($item);
    }

## Clear and Append all check items
    $slave_page->{param_check_ctrl}->Clear();
    foreach my $argument ( @{ $slave_page->{step}->{argument} } ) {
        next if !$argument->{id} or !$argument->{step};
        $slave_page->{param_check_ctrl}->Append( $argument->{id} );
    }

## Set Parameter Attributes
    $slave_page->{param_severity_ctrl}->SetValue( $param->{severity} );
    $slave_page->{param_method_ctrl}->SetValue( $param->{method} );
    $slave_page->{param_compare_ctrl}->SetValue( $param->{compare} );
    $slave_page->{param_check_ctrl}->SetValue( $param->{check} );
    $slave_page->{param_content_ctrl}->SetValue( $param->{content} );

## Set parameter's hint
    my $param_hint =
      $self->{ARF}->get_step_hint( $slave_page->{step}, $param->{id} );
    if ( $param_hint and $param_hint->{content} ) {
        $slave_page->{param_hint_ctrl}->SetValue( $param_hint->{content} );
    }
    else {
        $slave_page->{param_hint_ctrl}->SetValue("");
    }

## Return Ok
    return 1;
}

##############################################################################
#
# set_right_slave_refer()
#
# Set Right Slave Referrer
#
# Arguments expected are:
# - self          - Object reference
# - refer_id      - Referrer's Identifier

sub set_right_slave_refer {
    my ( $self, $refer_id ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Return Error if slave page not selected
    return 0
      if !$slave_page
          or !$slave_page->{step}
          or !$slave_page->{refer_id_ctrl};

## Split referrer Id
    my @id = split( /:/, $refer_id );
    my $refer_template = $id[0] if $id[0];
    my $refer_step     = $id[1] if $id[1];
    my $refer_param    = $id[2] if $id[2];

## Get Referrer
    my $refer =
      $main_page->{atf}
      ->get_step_refer( $slave_page->{step}, $refer_template, $refer_step,
        $refer_param );

## If referrer doesn't exist
    if ( !$refer ) {

## Log Message
        Wx::LogMessage("Referrer $refer_id doesn't exist");

## Return Error
        return 0;
    }

## Set Parameter Attributes
    $slave_page->{refer_content_ctrl}->SetValue( $refer->{content} );
    $slave_page->{refer_template_ctrl}->SetValue( $refer->{template} );
    $slave_page->{refer_step_ctrl}->SetValue( $refer->{step} );
    $slave_page->{refer_remote_ctrl}->SetValue( $refer->{remote} );

## Return Ok
    return 1;
}

##############################################################################
#
# set_right_slave_scenario()
#
# Set Right Slave Scenario
#
# Arguments expected are:
# - self          - Object reference
# - scenario_id      - Scenario's Identifier

sub set_right_slave_scenario {
    my ( $self, $scenario_id ) = @_;

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Get selected page in right
    my $slave_page = $main_page->GetPage( $main_page->GetSelection() );

## Return Error if slave page not selected
    return 0
      if !$slave_page
          or !$slave_page->{arf}
          or !$slave_page->{scenario_id_ctrl};

## Open STF
    my $scenario = new AFX::ATF( $slave_page->{arf}, $scenario_id, 'scenario' );

## If scenario doesn't exist
    if ( !$scenario ) {

## Log Message
        Wx::LogMessage("Scenario $scenario_id doesn't exist");

## Return Error
        return 0;
    }

## Save scenario
    $slave_page->{scenario} = $scenario;

## Clear step list
    $slave_page->{scenario_step_ctrl}->Clear();
    $slave_page->{scenario_step_ctrl}->SetValue('');

## Check steps in STF
    foreach my $step ( @{ $scenario->{_xml}->{step} } ) {

## Skip wrong step
        next if !$step->{id};

## Append Step
        $slave_page->{scenario_step_ctrl}->Append( $step->{id} );

## Set first value
        $slave_page->{scenario_step_ctrl}->SetValue( $step->{id} )
          if !$slave_page->{scenario_step_ctrl}->GetValue();
    }

## Return Ok
    return 1;
}

##############################################################################
#
# set_right_slave_source()
#
# Set Right Slave Source
#
# Arguments expected are:
# - self          - Object reference
# - main_page     - wxAuiNotebook
# - readonly      - Open as Readonly

sub set_right_slave_source {
    my ( $self, $main_page, $readonly ) = @_;

    use Wx qw(wxSTC_LEX_XML wxSTC_MARGIN_NUMBER
      wxSTC_MARK_ARROW wxNullColour wxRED wxLIGHT_GREY
      wxSTC_MOD_INSERTTEXT wxSTC_MOD_DELETETEXT
      wxSTC_H_DEFAULT wxSTC_H_TAG wxSTC_H_ATTRIBUTE wxSTC_H_DOUBLESTRING
      wxSTC_H_SINGLESTRING wxSTC_H_VALUE wxSTC_H_NUMBER);

## Add New Template into Right Notebook
    if ( !$main_page->{source} ) {

        $main_page->{source} = Wx::StyledTextCtrl->new( $self->{right_nb}, -1 );

## Set Margin and Marker
        $main_page->{source}->SetMarginType( 0, wxSTC_MARGIN_NUMBER );
        $main_page->{source}->SetMarginWidth( 0, 25 );
        $main_page->{source}
          ->MarkerDefine( 1, wxSTC_MARK_ARROW, wxNullColour, wxRED );
        $main_page->{source}->SetMarginWidth( 1, 15 );

## Set Modification Mask
        $main_page->{source}
          ->SetModEventMask( wxSTC_MOD_INSERTTEXT | wxSTC_MOD_DELETETEXT );

## Set Style and Attributes
        $main_page->{source}->StyleClearAll();
        $main_page->{source}->StyleSetSpec( wxSTC_H_DEFAULT,   "fore:#000000" );
        $main_page->{source}->StyleSetSpec( wxSTC_H_TAG,       "fore:#3F7F7F" );
        $main_page->{source}->StyleSetSpec( wxSTC_H_ATTRIBUTE, "fore:#7F007F" );
        $main_page->{source}
          ->StyleSetSpec( wxSTC_H_DOUBLESTRING, "fore:#2A00FF" );
        $main_page->{source}
          ->StyleSetSpec( wxSTC_H_SINGLESTRING, "fore:#2A00FF" );
        $main_page->{source}->StyleSetSpec( wxSTC_H_VALUE,  "fore:#2A00FF" );
        $main_page->{source}->StyleSetSpec( wxSTC_H_NUMBER, "fore:#2A00FF" );
        $main_page->{source}->SetLexer(wxSTC_LEX_XML);

## Set indent and tabs
        $main_page->{source}->SetUseTabs(0);
        $main_page->{source}->SetTabIndents(1);
        $main_page->{source}->SetBackSpaceUnIndents(1);
        $main_page->{source}->SetIndent(2);

## Set ATF Notebook Events
        Wx::Event::EVT_STC_CHANGE( $self, $main_page->{source},
            \&on_right_slave_source_changed );
    }

## Log Message
    Wx::LogMessage("DEBUG: Source updated from XML");

## Set Text
    $main_page->{source}->SetReadOnly(0);
    $main_page->{source}->SetText( $main_page->{atf}->get_xml() )
      if $main_page->{atf};
    $main_page->{source}->SetText( $main_page->{asf}->get_xml() )
      if $main_page->{asf};
    $main_page->{source}->EmptyUndoBuffer();

## Set source readonly to True
    $main_page->{source}->SetReadOnly(1) if $readonly;

## Return Ok
    return 1;
}

##############################################################################
#
# set_right_slave_page_property()
#
# Open ATF Property for Design
#
# Arguments expected are:
# - self          - Object reference
# - atf_id        - ATF's Identifier

sub set_right_slave_page_property {
    my ( $self, $atf_id ) = @_;

    use Wx qw(wxTE_MULTILINE wxHORIZONTAL wxVERTICAL wxALL wxEXPAND
      wxCENTRE);

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Set page text
    my $page_text = 'Property';

## Check all pages
    foreach my $page_num ( 0 .. $main_page->GetPageCount() ) {

## Skip if page not equal template
        next if $main_page->GetPageText($page_num) ne $page_text;

## Select already opened page
        $main_page->SetSelection($page_num);

## Return Error
        return 0;
    }

## Return Error if it's not ATF
    return 0 if $main_page->{atf}->get_id() ne $atf_id;

## Add New Template into Right Notebook
    my $panel = Wx::ScrolledWindow->new( $self->{right_nb}, -1 );

## Add page to notebook
    $main_page->AddPage( $panel, $page_text, 1 );

## Main sizer
    my $main_sizer = Wx::BoxSizer->new(wxVERTICAL);
    $panel->SetSizerAndFit($main_sizer);
    $panel->SetScrollRate( 1, 1 );

## Add machine static box
    my $validation_sizer =
      Wx::StaticBoxSizer->new( Wx::StaticBox->new( $panel, -1, "&Validation" ),
        wxVERTICAL );
    $main_sizer->Add( $validation_sizer, 0, wxEXPAND );

## Add Machine Id sizer
    my $machine_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $validation_sizer->Add( $machine_sizer, 0, wxALL, 2 );

## Add Machine Id into sizer
    $machine_sizer->Add( Wx::StaticText->new( $panel, -1, "Machine: " ),
        0, wxCENTRE );
    $panel->{machine_id_ctrl} = Wx::ComboBox->new( $panel, -1 );
    $machine_sizer->Add( $panel->{machine_id_ctrl}, 0, wxALL );

## Set Machine Id Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{machine_id_ctrl},
        \&on_right_slave_valid_machine_id_changed
    );

## Add New machine button
    my $new_machine = Wx::Button->new( $panel, -1, 'New' );
    $machine_sizer->Add( $new_machine, 0, wxALL );

## Add Machine Attr into sizer
    my $machine_attr_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $machine_sizer->Add( $machine_attr_sizer, 0, wxALL, 2 );

## Check all machines in ATF
    my @machines;
    foreach my $machine ( @{ $main_page->{atf}->{_xml}->{machine} } ) {
        next if !$machine->{id};
        push( @machines, $machine->{id} );
        $panel->{machine_id_ctrl}->Append( $machine->{id} );
    }

## If machines specified
    if ( @machines and $machines[0] ) {

## Set first machine
        $panel->{machine_id_ctrl}->SetValue( $machines[0] );
        $self->set_right_slave_valid_machine( $machines[0] );
    }

## Page Layout
    $self->set_right_slave_layout();

## Return Ok
    return 1;
}

##############################################################################
#
# set_right_slave_page_rcmd()
#
# Open ASF Rcmd
#
# Arguments expected are:
# - self          - Object reference
# - mach_id       - Machine's Identifier
# - mach_unit     - Machine's Unit

sub set_right_slave_page_rcmd {
    my ( $self, $mach_id, $mach_unit ) = @_;

    use Wx qw(wxTE_MULTILINE wxHORIZONTAL wxVERTICAL wxALL wxEXPAND
      wxCENTRE wxTE_PROCESS_ENTER wxTELETYPE wxNORMAL);

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Set page text
    my $page_text = "RCmd:$mach_id";

## Check all pages
    foreach my $page_num ( 0 .. $main_page->GetPageCount() ) {

## Skip if page not equal template
        next if $main_page->GetPageText($page_num) ne $page_text;

## Select already opened page
        $main_page->SetSelection($page_num);

## Return Error
        return 0;
    }

## Get Machine
    my $machine = $main_page->{asf}->get_machine( $mach_id, $mach_unit );

## Return Error if machine not found
    return 0 if !$machine;

## Create Process
    my $process =
      new AFX::Process( $self->{Process}->{ACF}, $main_page->{asf}, 'rcmd' );

## If process wasn't created
    if ( !$process ) {

## Log Message
        Wx::LogMessage( $self->{Process}->{ACF}->message_failed_process() );

## Return Error
        return 0;
    }

## Add New Machine into Right Notebook
    my $panel = Wx::ScrolledWindow->new( $self->{right_nb}, -1 );

## Set Machine and Process to panel
    $panel->{machine} = $machine;
    $panel->{process} = $process;

## Define Scenario, Units and Machines
    my @scenarios = ('RCMD');
    my @units     = split( /,/, uc($mach_unit) );
    my @machines  = split( /,/, uc($mach_id) );
    my $login     = "root";

## Add machine for processing
    $process->add_machine( \@units, \@machines );

## Set noprompt mode
    $process->set_noprompt();

## Generate hash for ARF
    my $arf = new AFX::ARF( $process, $machine, 'rcmd', $scenarios[0] );
    $panel->{arf}       = $arf;
    $panel->{login}     = $login;
    $panel->{templates} = \@scenarios;
    $panel->{step_id}   = 1;

## Add page to notebook
    $main_page->AddPage( $panel, $page_text, 1 );

## Main sizer
    my $main_sizer = Wx::BoxSizer->new(wxVERTICAL);
    $panel->SetSizerAndFit($main_sizer);
    $panel->SetScrollRate( 1, 1 );

## Add Rcmd into sizer
    $panel->{rcmd_output_ctrl} =
      new Wx::TextCtrl( $panel, -1, "", wxDefaultPosition, wxDefaultSize,
        wxTE_MULTILINE );
    $main_sizer->Add( $panel->{rcmd_output_ctrl}, 1, wxALL | wxEXPAND, 2 );
    $panel->{rcmd_output_ctrl}
      ->SetFont( Wx::Font->new( 10, wxTELETYPE, wxNORMAL, wxNORMAL ) );

## Set Master
    $panel->{rcmd_output_ctrl}->SetValue( $arf->message_processing() . "\n\n" );

## Add Input static box
    my $input_sizer =
      Wx::StaticBoxSizer->new(
        Wx::StaticBox->new( $panel, -1, "&Remote Command Execution" ),
        wxVERTICAL );
    $main_sizer->Add( $input_sizer, 0, wxEXPAND );

## Add Input Command sizer
    my $input_cmd_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $input_sizer->Add( $input_cmd_sizer, 0, wxALL | wxEXPAND, 2 );

## Add Input
    $input_cmd_sizer->Add(
        Wx::StaticText->new( $panel, -1, "$login@" . "rcmd>" ),
        0, wxCENTRE );
    $panel->{rcmd_input_ctrl} =
      new Wx::TextCtrl( $panel, -1, "", wxDefaultPosition, wxDefaultSize,
        wxTE_PROCESS_ENTER );
    $input_cmd_sizer->Add( $panel->{rcmd_input_ctrl}, 2, wxALL | wxEXPAND, 2 );
    Wx::Event::EVT_TEXT_ENTER(
        $self,
        $panel->{rcmd_input_ctrl},
        \&on_right_slave_rcmd_execute_button
    );

## Add Execte Button
    my $execute_input = Wx::Button->new( $panel, -1, 'Execute' );
    $input_cmd_sizer->Add( $execute_input, 0, wxCENTRE, 2 );
    Wx::Event::EVT_BUTTON( $self, $execute_input,
        \&on_right_slave_rcmd_execute_button );

## Add Input Command sizer
    my $input_scenario_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $input_sizer->Add( $input_scenario_sizer, 0, wxALL | wxEXPAND, 2 );

## Add Scenario
    $input_scenario_sizer->Add( Wx::StaticText->new( $panel, -1, "Scenario:" ),
        0, wxCENTRE );
    $panel->{scenario_id_ctrl} = new Wx::ComboBox( $panel, -1 );
    $input_scenario_sizer->Add( $panel->{scenario_id_ctrl},
        2, wxALL | wxEXPAND, 2 );

## Set Scenario Id Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{scenario_id_ctrl},
        \&on_right_slave_scenario_id_changed
    );

## Add Steps
    $input_scenario_sizer->Add( Wx::StaticText->new( $panel, -1, ":" ),
        0, wxCENTRE );
    $panel->{scenario_step_ctrl} = new Wx::ComboBox( $panel, -1 );
    $input_scenario_sizer->Add( $panel->{scenario_step_ctrl},
        2, wxALL | wxEXPAND, 2 );

## Add Run Scenario Button
    my $run_scenario_input = Wx::Button->new( $panel, -1, 'Run' );
    $input_scenario_sizer->Add( $run_scenario_input, 0, wxCENTRE, 2 );
    Wx::Event::EVT_BUTTON( $self, $run_scenario_input,
        \&on_right_slave_rcmd_run_scenario_button );

## Find STF
    my $stfnames = $self->{Process}->{ACF}->find_atf( 'scenario', "RCMD.*" );

## Check if scenario exist
    if ( $stfnames and $stfnames->[0] ) {

## Check templates
        foreach my $stfname ( @{$stfnames} ) {

## Open STF
            my $stf = new AFX::ATF( $arf, $stfname, 'scenario' );

## if STF invalid
            next if !$stf;

## Append Scenario
            $panel->{scenario_id_ctrl}->Append( $stf->get_id() );
        }

## Set first scenario
        $panel->{scenario_id_ctrl}->SetValue('RCMD');
        $self->set_right_slave_scenario('RCMD');
    }

## Page Layout
    $self->set_right_slave_layout();

## Return Ok
    return 1;
}

##############################################################################
#
# set_right_slave_page_step()
#
# Open ATF Step for Design
#
# Arguments expected are:
# - self          - Object reference
# - step_id       - Step's Identifier

sub set_right_slave_page_step {
    my ( $self, $step_id ) = @_;

    use Wx qw(wxTE_MULTILINE wxHORIZONTAL wxVERTICAL wxALL wxEXPAND
      wxCENTRE);

## Get selected page
    my $main_page =
      $self->{right_nb}->GetPage( $self->{right_nb}->GetSelection() );

## Check all pages
    foreach my $page_num ( 0 .. $main_page->GetPageCount() ) {

## Skip if page not equal template
        next if $main_page->GetPageText($page_num) ne $step_id;

## Select already opened page
        $main_page->SetSelection($page_num);

## Return Error
        return 0;
    }

## Get Step
    my $step = $main_page->{atf}->get_step($step_id);

## Return Error if step not found
    return 0 if !$step;

## Add New Template into Right Notebook
    my $panel = Wx::ScrolledWindow->new( $self->{right_nb}, -1 );

## Set Step to panel
    $panel->{step} = $step;

## Add page to notebook
    $main_page->AddPage( $panel, $step_id, 1 );

## Main sizer
    my $main_sizer = Wx::BoxSizer->new(wxVERTICAL);
    $panel->SetSizerAndFit($main_sizer);
    $panel->SetScrollRate( 1, 1 );

## Add command static box
    my $hint_sizer =
      Wx::StaticBoxSizer->new( Wx::StaticBox->new( $panel, -1, "&Hint" ),
        wxVERTICAL );
    $main_sizer->Add( $hint_sizer, 0, wxEXPAND );

## Show hint
    $panel->{hint_ctrl} =
      new Wx::TextCtrl( $panel, -1, "", wxDefaultPosition, wxDefaultSize,
        wxTE_MULTILINE );
    $hint_sizer->Add( $panel->{hint_ctrl}, 1, wxALL | wxEXPAND, 2 );

## Set Hint Event
    Wx::Event::EVT_TEXT( $self, $panel->{hint_ctrl},
        \&on_right_slave_hint_changed );

## Add command static sizer
    my $command_sizer =
      Wx::StaticBoxSizer->new( Wx::StaticBox->new( $panel, -1, "&Command" ),
        wxVERTICAL );
    $main_sizer->Add( $command_sizer, 0, wxEXPAND );

## Show command
    $panel->{command_content_ctrl} = new Wx::TextCtrl( $panel, -1, "" );
    $command_sizer->Add( $panel->{command_content_ctrl},
        1, wxALL | wxEXPAND, 2 );

## Set Command Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{command_content_ctrl},
        \&on_right_slave_command_content_changed
    );

## Add Command login sizer
    my $command_login_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $command_sizer->Add( $command_login_sizer, 0, wxALL, 2 );

## Add Login into sizer
    $command_login_sizer->Add( Wx::StaticText->new( $panel, -1, "Login: " ),
        0, wxCENTRE );
    $panel->{command_login_ctrl} = Wx::ComboBox->new( $panel, -1 );
    $command_login_sizer->Add( $panel->{command_login_ctrl}, 0, wxALL );

## Set Login Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{command_login_ctrl},
        \&on_right_slave_command_login_changed
    );

## Add Command timeout
    $command_login_sizer->Add( Wx::StaticText->new( $panel, -1, "Timeout: " ),
        0, wxCENTRE );
    $panel->{command_timeout_ctrl} = Wx::TextCtrl->new( $panel, -1, "" );
    $command_login_sizer->Add( $panel->{command_timeout_ctrl},
        0, wxALL | wxCENTRE );

## Set Timeout Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{command_timeout_ctrl},
        \&on_right_slave_command_timeout_changed
    );

## Add Command remote
    $panel->{command_remote_ctrl} =
      Wx::CheckBox->new( $panel, -1, "Remote", wxDefaultPosition, wxDefaultSize,
        wxCENTRE );
    $command_login_sizer->Add( $panel->{command_remote_ctrl},
        0, wxALL | wxCENTRE );

## Add Command attributes sizer
    my $command_attr_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $command_sizer->Add( $command_attr_sizer, 0, wxALL, 2 );

## Add Command end
    $command_attr_sizer->Add( Wx::StaticText->new( $panel, -1, "End: " ),
        0, wxCENTRE );
    $panel->{command_end_ctrl} = Wx::TextCtrl->new( $panel, -1, "" );
    $command_attr_sizer->Add( $panel->{command_end_ctrl}, 0, wxALL | wxCENTRE );

## Set End Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{command_end_ctrl},
        \&on_right_slave_command_end_changed
    );

## Add Command passwd
    $command_attr_sizer->Add( Wx::StaticText->new( $panel, -1, " Password: " ),
        0, wxCENTRE );
    $panel->{command_passwd_ctrl} = Wx::ComboBox->new( $panel, -1 );
    $command_attr_sizer->Add( $panel->{command_passwd_ctrl},
        0, wxALL | wxCENTRE );

## Set Passwd Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{command_passwd_ctrl},
        \&on_right_slave_command_passwd_changed
    );

## Set Parameter pane
    my $param_pane   = Wx::CollapsiblePane->new( $panel, -1, 'Parameter' );
    my $param_sizer  = Wx::BoxSizer->new(wxVERTICAL);
    my $param_window = $param_pane->GetPane();
    $param_window->SetSizerAndFit($param_sizer);
    $param_sizer->SetSizeHints($param_window);
    Wx::Event::EVT_COLLAPSIBLEPANE_CHANGED( $self, $param_pane,
        sub { $self->set_right_slave_layout(); } );
    $main_sizer->Add( $param_pane, 0, wxEXPAND );

## Add Param Id sizer
    my $param_id_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $param_sizer->Add( $param_id_sizer, 0, wxALL, 2 );

## Add Param Id into sizer
    $param_id_sizer->Add( Wx::StaticText->new( $param_window, -1, "Id: " ),
        0, wxCENTRE );
    $panel->{param_id_ctrl} = Wx::ComboBox->new( $param_window, -1 );
    $param_id_sizer->Add( $panel->{param_id_ctrl}, 0, wxALL );

## Set Parameter Id Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{param_id_ctrl},
        \&on_right_slave_param_id_changed
    );

## Add New paramer button
    my $new_param = Wx::Button->new( $param_window, -1, 'New' );
    $param_id_sizer->Add( $new_param, 0, wxALL );

## Add Param Attr into sizer
    my $param_attr_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $param_sizer->Add( $param_attr_sizer, 0, wxALL, 2 );

## Add Param Method into sizer
    $param_attr_sizer->Add(
        Wx::StaticText->new( $param_window, -1, "Method: " ),
        0, wxCENTRE );
    $panel->{param_method_ctrl} = Wx::ComboBox->new( $param_window, -1 );
    $param_attr_sizer->Add( $panel->{param_method_ctrl}, 0, wxALL );

## Add Param Severity into sizer
    $param_attr_sizer->Add(
        Wx::StaticText->new( $param_window, -1, " Severity: " ),
        0, wxCENTRE );
    $panel->{param_severity_ctrl} = Wx::ComboBox->new( $param_window, -1 );
    $param_attr_sizer->Add( $panel->{param_severity_ctrl}, 0, wxALL );

## Add Param Attr2 into sizer
    my $param_attr2_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $param_sizer->Add( $param_attr2_sizer, 0, wxALL, 2 );

## Add Param Compare into sizer
    $param_attr2_sizer->Add(
        Wx::StaticText->new( $param_window, -1, "Compare: " ),
        0, wxCENTRE );
    $panel->{param_compare_ctrl} = Wx::ComboBox->new( $param_window, -1 );
    $param_attr2_sizer->Add( $panel->{param_compare_ctrl}, 0, wxALL );

## Add Param Check into sizer
    $param_attr2_sizer->Add(
        Wx::StaticText->new( $param_window, -1, " Check: " ),
        0, wxCENTRE );
    $panel->{param_check_ctrl} = Wx::ComboBox->new( $param_window, -1 );
    $param_attr2_sizer->Add( $panel->{param_check_ctrl}, 0, wxALL );

## Add Param Hint into sizer
    my $param_hint_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $param_sizer->Add( $param_hint_sizer, 0, wxALL | wxEXPAND, 2 );

## Show parameter Hint
    $param_hint_sizer->Add( Wx::StaticText->new( $param_window, -1, "Hint: " ),
        0, wxCENTRE );
    $panel->{param_hint_ctrl} = new Wx::TextCtrl( $param_window, -1, "" );
    $param_hint_sizer->Add( $panel->{param_hint_ctrl}, 1, wxALL | wxEXPAND, 2 );

## Add Param Rule into sizer
    my $param_rule_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $param_sizer->Add( $param_rule_sizer, 0, wxALL | wxEXPAND, 2 );

## Show parameter Content
    $param_rule_sizer->Add( Wx::StaticText->new( $param_window, -1, "Rule: " ),
        0, wxCENTRE );
    $panel->{param_content_ctrl} = new Wx::TextCtrl( $param_window, -1, "" );
    $param_rule_sizer->Add( $panel->{param_content_ctrl},
        1, wxALL | wxEXPAND, 2 );

## Set Referrer pane
    my $refer_pane   = Wx::CollapsiblePane->new( $panel, -1, 'Referrer' );
    my $refer_sizer  = Wx::BoxSizer->new(wxVERTICAL);
    my $refer_window = $refer_pane->GetPane();
    $refer_window->SetSizerAndFit($refer_sizer);
    Wx::Event::EVT_COLLAPSIBLEPANE_CHANGED( $self, $refer_pane,
        sub { $self->set_right_slave_layout(); } );
    $main_sizer->Add( $refer_pane, 0, wxEXPAND );

## Add Refer Id sizer
    my $refer_id_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $refer_sizer->Add( $refer_id_sizer, 0, wxALL, 2 );

## Add Refer Id into sizer
    $refer_id_sizer->Add( Wx::StaticText->new( $refer_window, -1, "Id: " ),
        0, wxCENTRE );
    $panel->{refer_id_ctrl} = Wx::ComboBox->new( $refer_window, -1 );
    $refer_id_sizer->Add( $panel->{refer_id_ctrl}, 0, wxALL );

## Set Parameter Id Event
    Wx::Event::EVT_TEXT(
        $self,
        $panel->{refer_id_ctrl},
        \&on_right_slave_refer_changed
    );

## Add New refer button
    my $new_refer = Wx::Button->new( $refer_window, -1, 'New' );
    $refer_id_sizer->Add( $new_refer, 0, wxALL );

## Add Refer Attr into sizer
    my $refer_attr_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $refer_sizer->Add( $refer_attr_sizer, 0, wxALL, 2 );

## Add Refer Parameter into sizer
    $refer_attr_sizer->Add(
        Wx::StaticText->new( $refer_window, -1, "Parameter: " ),
        0, wxCENTRE );
    $panel->{refer_content_ctrl} = Wx::ComboBox->new( $refer_window, -1 );
    $refer_attr_sizer->Add( $panel->{refer_content_ctrl}, 0, wxALL );

## Add Refer Step into sizer
    $refer_attr_sizer->Add( Wx::StaticText->new( $refer_window, -1, " Step: " ),
        0, wxCENTRE );
    $panel->{refer_step_ctrl} = Wx::ComboBox->new( $refer_window, -1 );
    $refer_attr_sizer->Add( $panel->{refer_step_ctrl}, 0, wxALL );

## Add Refer Attr2 into sizer
    my $refer_attr2_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
    $refer_sizer->Add( $refer_attr2_sizer, 0, wxALL, 2 );

## Add Refer Template into sizer
    $refer_attr2_sizer->Add(
        Wx::StaticText->new( $refer_window, -1, "Template: " ),
        0, wxCENTRE );
    $panel->{refer_template_ctrl} = Wx::ComboBox->new( $refer_window, -1 );
    $refer_attr2_sizer->Add( $panel->{refer_template_ctrl}, 0, wxALL );

## Add Referrer remote
    $panel->{refer_remote_ctrl} =
      Wx::CheckBox->new( $refer_window, -1, "Remote", wxDefaultPosition,
        wxDefaultSize, wxCENTRE );
    $refer_attr2_sizer->Add( $panel->{refer_remote_ctrl}, 0, wxALL | wxCENTRE );

## Set Static pane
    my $static_pane   = Wx::CollapsiblePane->new( $panel, -1, 'Static' );
    my $static_sizer  = Wx::BoxSizer->new(wxVERTICAL);
    my $static_window = $static_pane->GetPane();
    $static_window->SetSizerAndFit($static_sizer);
    $static_sizer->SetSizeHints($static_window);
    Wx::Event::EVT_COLLAPSIBLEPANE_CHANGED( $self, $static_pane,
        sub { $self->set_right_slave_layout(); } );
    $main_sizer->Add( $static_pane, 0, wxEXPAND );

## Show Static
    $panel->{static_ctrl} =
      new Wx::TextCtrl( $static_window, -1, "", wxDefaultPosition, [ -1, 100 ],
        wxTE_MULTILINE );
    $static_sizer->Add( $panel->{static_ctrl}, 1, wxALL | wxEXPAND, 2 );

## Add Check Static button
    my $check_static =
      Wx::Button->new( $static_window, -1, 'Check and save static' );
    $static_sizer->Add( $check_static, 0, wxALL );
    Wx::Event::EVT_BUTTON( $self, $check_static,
        \&on_right_slave_static_check_button );

## Add check HTML
    $panel->{static_html} =
      Wx::HtmlWindow->new( $static_window, -1, wxDefaultPosition, [ -1, 100 ] );
    $static_sizer->AddWindow( $panel->{static_html}, 1, wxALL | wxEXPAND, 2 );

## Set Command
    $self->set_right_slave_command();
    $self->on_right_slave_static_check_button();

## Check all parameters in step
    my @params;
    foreach my $param ( @{ $panel->{step}->{param} } ) {
        next if !$param->{id};
        push( @params, $param->{id} );
        $panel->{param_id_ctrl}->Append( $param->{id} );
    }

## If parameters specified
    if ( @params and $params[0] ) {

## Set first parameter
        $panel->{param_id_ctrl}->SetValue( $params[0] );
        $self->set_right_slave_param( $params[0] );
    }

## Check referrers in Step
    my @refers;
    foreach my $refer ( @{ $panel->{step}->{refer} } ) {
        next if !$refer->{content};
        my $refer_id =
          $refer->{template} . ":" . $refer->{step} . ":" . $refer->{content};
        $panel->{refer_id_ctrl}->Append($refer_id);
        push( @refers, $refer_id );
    }

## If referrers specified
    if ( @refers and $refers[0] ) {

## Set Referrer
        $panel->{refer_id_ctrl}->SetValue( $refers[0] );
        $self->set_right_slave_refer( $refers[0] );
    }

## Page Layout
    $self->set_right_slave_layout();

## Return Ok
    return 1;
}

##############################################################################
#
# show_about()
#
# Dialog: Frame About
#
# Arguments expected are:
# - Process's Object
# - ARF's Object

sub show_about {
    my ( $self, $event ) = @_;

## Create Dialog
    my $info = Wx::AboutDialogInfo->new();

## Set Dialog properties
    $info->SetName( $self->{title} );
    $info->SetVersion( $self->{version} );

## Show About Dialog
    Wx::AboutBox($info);

## Return Ok
    return 1;
}

1;
